А. Александреску - Современное проектирование на C++ (1119444), страница 61
Текст из файла (страница 61)
В классе лазу1ече1впевугастогу класс ть1зт был известен под именем тчгвьтзт 3 (в111уво1д1ег, в111умопатег, 3111увцрегмопзтег). При использовании шаблона проектирования Раттегп класс ть1зт становится неуме- стным. Однако класс ть1зт по-прежнему необходим классу пепь1пеагн1егагсйу для генерации отдельного класса для каждого изделия, указанного в списке абстрактных изделий.
Что делать? В этой ситуации естественно передать список абстрактных изделий классу соп- сгетегастогу в качестве аргумента ть1зт. Теперь класс пепь1пеагн1егагсЬу сможет генерировать правильное количество классов, а изменять реализацию класса Соп- сгетегастогу не понадобится. Объявление класса сопсгетегастогу принимает следующий вид. тевр1ате < с1аьа лЬзтгастгаст, тевр1ате <с1азз, с1азз> с1азз сгеатог, с1азз ть1зт = турепаве лЬзтгастгаст::Ргодцсть1зт > с1азз Сопсгетегастогу; Напомним, что определение класса лЬзтгастгаст, приведенное в разделе 9.3, содержит внутренний класс Ргодцстьйзт.
Перейдем теперь к реализации шаблонного класса РгототуреГастогуцп1т, солержащего прототип и вызывающего функцию с1опе. Его реализация намного проще, чем реализация класса орнепГастогуоп1т, поскольку вместо двух списков типов класс Ргототурегастогуцпйт работает только с одним списком абстрактных изделий.
тевр1ате <с1аьа сопсгетеггодцст, с1ааа ваке> с1азз РгототуреГастогуцпзт : рцЬ11с вазе туредет турепаве вазе::Ргодисть1зт вазеггодист11зт; рготестед: туредет турепаве вазе::Ргодисть1зт та11ггодцст11зт; рцЬ11с: туредет турепаве вазе::Ргодцсть1зт::неад лЬзтгастггодцст; Ргототурегастогуцп1т(лЬзтгастггодист* р = 0); рггототуре (р) () бг1епд чо1д побетггототуре(сонат РгототуреГастогуоп1та ве, лЬзтгастггодист"б рггототуре) рггототуре = ве.рггототуре 250 Часть П.
Компоненты тг1епд чо)д оовесггототуре(гготоСуреГастогуип1сй ве, АЬзсгассггодисс" роЬ)) ( ве.рргоСотуре =рОЬ); ) севр1асе <с1азз и> чо)д аесггососуре(АЬзсгассггодисс*Ф р) ( геСигп Ооаетггототуре(*СЬ1з, р); севр1асе <с1азз и> чо)д БетггототуРЕ(0* РОЬ)) ( ОоветггОСОСУРЕ(*СЬ1З, РОЬ)); АЬзсгассргодисс* оосгеасе(туре2туре<АЬзсгассггодисс>) ( аззегс(рггососуре ); геСигп рргоСотуре ->С1опеО; рг1часе: АЬзсгассггодисС* ргготоСуре ; Шаблонный класс Ргососурегассогуип)с основан на некоторых предположениях. Во-первых, он не владеет своим прототипом.
Можно потребовать, чтобы функция 5етггоСотуре удаляла старый прототип перед его переприсваиванием, Во-вторых, класс РгоСоСурегастогуип)с использует функцию с1апе, предположительно клонируюшую объект. В конкретном приложении можно использовать другое имя, руководствуясь собственными вкусами или требованиями, предъявляемыми библиотекой.
Если нужно настроить фабрику, основанную на применении прототипов, достаточно написать шаблонный класс, аналогичный классу Ргососурегассогуип)с. Для этого можно применить механизм наследования, сделав класс Ргососурегассогуип)с базовым и замещая соответствуюшие функции. Допустим, что мзк решили реализовать функцию оосгеасе так, чтобы она возврашала нулевой указатель„если указатель на прототип равен нулю. севр1асе <с1азз АЬзсгассггодисс, с1азз вазе> с1азз мугассогуип1с : риЫ)с Ргососурегассогуип)с<АЬзсгассггодисс, вазе> ( риЫдс: // Реализуем Функцию ооегеасе так, чтобы она допускала // нулевой указатель на прототип АЬзсгассггодисс* оосгеасе(туре2туре<АЬзсгассргодисс>) ( геСигп рггототурв ? ргготоСУре ->С!опеО : О; Вернемся к нашей компьютерной игре. Для того чтобы определить конкретную фабрику, нам нужно написать следующий код приложения. // Код приложения суредет сопсгесегассогу АЬзсгассепевугассогу, Ргососурегассогуипзс > Епевугассогу; 251 Глава 9.
Шаблон АЬанасс Еаозогу Итак, дуэт классов АЬзсгассгассогу/сопсгесегассогу предоставляет нам следующие возможности. ° Легко определять фабрики с помощью списков типов. ° Поскольку класс АЬзсгассгассогу наследует каждый из своих компонентов, его интерфейс обладает высокой модульностью. Отдельные указатели или ссылки на подобъекты класса АГоп(с<т> можно передавать разным модулям, уменьшая общую взаимозависимость классов. ° Лля реализапии класса АЬзсгассгассогу можно применить класс сопсгесегассогу, используя стратегию, диктующую метод создания объектов. Статически связанным стратегиям создания объектов (таким как класс орнепгассогуши с, использующий оператор пеп) нужно передавать список конкретных изделий, создаваемых фабрикой.
° Наиболее распространенной стратегией создания объектов является шаблон проектирования Ргососуре. Эту стратегию можно легко реализовать в классе СопсгетеГасСогу с помошьЮ Шаблонного класса РготоСуреГастогупп1с. Попробуйте получить все перечисленные выше преимущества, реализовав шаблон проектирования АЬзсгасс гассогу вручную, 9.5. Резюме Шаблон проектирования АЬзсгасс гассогу -- интерфейс для создания семейства связанных или взаимозависимых полиморфных объектов.
Используя этот шаблон, можно разделить классы реализации на разные непересекающиеся семейства. Интерфейс обобщенной абстрактной фабрики можно реализовать с помощью списков типов и шаблонных стратегий. Списки типов предусматривают списки изделий (конкретных и абстрактных) и шаблонные стратегии. Шаблонный класс АЬзсгассгассогу представляет собой скелет для определения абстрактных фабрик в сочетании с шаблонным классом Агопзс, Класс АЬзсгассгассогу использует класс Сепзсассегн(егагспу (глава 3) для генерирования модульного интерфейса, наследующего класс АГОпз' С<т> для каждого абстрактного изделия т, указанного в списке типов. Эта структура позволяет уменьшить взаимозависимость классов, передавая в различные части приложения только отдельные модули фабрик. Шаблон СопсгеСеГастогу позволяет реализовать интерфейс класса АЬзсгассгассогу.
Класс сопсгесегассогу использует для создания объектов стратегию гассогущис и класс аепсзпеагн(егагсйу (глава 3). В библиотеке (ок1 ПРеДУсмотРены две реализаиии стратегии гассогуопзс: класс опнеигассогуоп(с, создающий объекты с помощью оператора пеп, и класс РгоСоСуреГастогуппзт, создающий объекты с помощью клонирования прототипов. 9.6. Краткий обзор классов АЬв1гасФРас1огу и Сопсге1еРас1огу ° Объявление класса АЬзсгассгассогу выглядит следующим образом. сеяр)асе < с)азз тс(зс, 252 Часть!Ь Компоненты семр1асе <с1аьв> с1авв цпзс = АЬзсгассгассогуип(с > с1ава АЬзсгассгассогу; Здесь класс ть(зс является списком типов, состояшим из абстрактных изделий.
созлаваемых фабрикой, а класс цп(с — зто шаблон, определяюший интерфейс каждого типа из списка тьз зС. Например, приведенное ниже выражение определяет абстрактную фабрику, способную клонировать объекты классов 5о1Нег, МопзСег и 5ирегМопзсег. суредеЕ АЬзсгассгассогу<ттгеьт5т 3(5о1Нег, мопзсег, 5ирегМопзтег> АЬзсгассепемугассогу; ° Класс АЬзсгассгассогуипзс<т> определяет интерфейс, состояший из чисто виртуальных функций, имеющих сигнатуру т* посгеасе(туре<туре<туре>).
Обычно функцию оосгеасе не нужно вызывать явно. Вместо нее вызывается фуНКцИЯ АЬзсгассгассогу::сгеасе. « Класс АЬзсгассгассогу содержит шаблонную функцию сгеасе, которую можно конкретизировать лля любого из типов абстрактных изделий'. АЬзсгассепепугассогу *ргассогу = ...; 5о1Нег «р5о1Нег = ргассогу->сгеасе<5о1Нег>О; ° Для реализации интерфейса, определенного классом АЬзсгассгассогу, библиотека (.о)п' содержит шаблонный класс сопсгесегассогу.
семр1асе < с1азз АЬзсгассгасс, сеер1асе <с1азз, с1азз> с1аав гассогуцп(с = орнеигассогуцпзс, с1ава ть(зс = АЬзсгассгасс::ггодцссеззс > с1аьв сопсгесегассогу; Здесь класс АЬзсгассгасс представляет собой конкретизацию класса АЬзсгассгассогу, подлежашего реализации, Класс гассогуцп(с является реализацией стратегии гассогуцптс, а класс тетзс — зто список конкретных изделий.
° Класс гассогуцМс имеет доступ к абстрактному и конкретному изделиям, подлежашим созданию. В библиотеке ).о)п' определены две стратегии сгеасог: классы орнеигассогуип(с (раздел 9.3) и ггососурегассогуцпзс (раздел 9.4). Их люжно использовать для настраиваемой реализации стратегии гассогцптС. ° Класс орнепгассогуцп(с использует для создания обьектов оператор пеп. Применяя этот класс, нужно передавать список типов, состояший из типов конкретных изделий, в качестве третьего шаблонного параметра класса Сопсгесегассогу. суребеЕ сопсгесегассогу < Аьзсгассепееугассогу, орнеигассогуцп(с, тугеес5т 3(5311уво1Нег, 5311умопзсег, 5(11у5ирегмопзтег) > Еазуьече1ЕпемуГасСогу; Глава 9.
Шаблон АЬв(гас1 Гас(огу 253 ° Класс ргосотурегастогуопз т хранит указатели на типы абстрактных изделий и создает новые объекты, вызывая функцию-член С1опе с соответствующими параметрами. Для этого в классе Рготосурекассогуцпзт для каждого абстрактного изделия т нужно определить отдельную виртуальную функцию с1опе, возврашаюшую указатель типа т* и дублируюшую объект. ° При использовании класса пгототурегассогуцпзт в сочетании с классом сопсгетегассогу третий шаблонный аргумент класса сопсгетеяастогу не нужен. туредеУ Сопсгесегастогу лбзсгассапеиугассогу, ргототуресастогуцпбт > апеиупгодист; 254 Часть Н. Компоненты ШАБЛОН Ч!8!ТОй В этой главе обсуждаются обобщенные компоненты, использующие шаблон проектирования Фз1тог (Сзаеща ег а1., 1995). Это мощный шаблон проектирования, изменяющий зависимость между проектными решениями, принятыми при разработке класса. Шаблон Мэ(тог (Инспектор) обеспечивает удивительную гибкость: в иерархию классов можно добавлять виртуальные функции, не прибегая к повторной компиляции ни этих функций, ни существующих клиентских кодов.
Однако эта гибкость достигается за счет определенных жертв; в иерархию теперь невозможно добавить новый терминальный класс (!еа( с1азз), не повторив компиляцию всей иерархии и ее клиентов. Следовательно, область применения шаблона Фз1тог ограничивается только очень устойчивыми иерархиями (в которые редко добавляются новые классы) и программами, в которые часто приходится добавлять новые виртуальные функции. Шаблон згтвттог противоречит программистской интуиции.