Анимация
JavaScript


Главная  Библионтека 

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 [ 75 ] 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105

в этой ситуации на помощь приходит шаблон Abstract Factory при условии, что он достаточно гибок и позволяет легко реализовать новый механизм распределения памяти и передачи аргументов конструктору.

Напомним, что шаблонный класс GenScatterHierarchy, описанный в главе 3, конкретизирует базовый шаблон, предоставленный пользователем, для каждого типа, приведенного в списке типов. По своей структуре полученная в результате конкретизация класса GenScatterHierarchy наследует все конкретизации шаблона, предоставленного пользователем. Иными словами, если есть шаблон unit и список типов TList, то класс GenScatte("Hierarchy<TList, unit> является наследником класса unit<T> для каждого типа т, указанного в списке TList.

Класс GenScatterHierarchy может оказаться очень полезным для определения интерфейса абстрактной фабрики - программисту достаточно определить интерфейс, который способен создавать объекты определенного типа, а затем применить этот интерфейс к нескольким типам с помощью класса GenScatterHierarchy.

Интерфейс, способный создавать объекты обобщенного класса т, выглядит следующим образом.

template <class т>

class AbstractFactoryunit

public:

virtual T* DoCreate(Type2Type<T> = 0); virtual ~AbstractFactoryunit() {}

Этот небольшой шаблон выглядит вполне прилично - виртуальный конструктор и ничего больше, - но зачем здесь класс Туре2туре? Как указывалось в главе 2, класс туре2туре - это простой шаблон, единственное предназначение которого - обеспечить однозначный выбор перегруженных функций. Ладно, но где тут перегруженные функции? Ведь в классе AbstractFactoryunit определяется только одна функция Do-Create. Однако одной и той же иерархии классов могут принадлежать разные конкретизации класса AbstractFactoryunit. Класс Туре2туре<т> позволяет избежать неоднозначности выбора разных вариантов перегруженной функции DoCreate.

Обобщенный интерфейс AbstractFactory использует класс GenScatterHierarchy в сочетании с классом AbstractFactoryunit.

template <

class TList,

template <class> class unit = AbstractFactoryunit

>

class AbstractFactory : public GenScatterHierarchy<TList, Unit> {

public:

typedef TList ProductList; template <class т> т* CreateC) {

unit <T>& unit = *this;

return unit.D0CreateCType2Type<T>C));

Виртуальные конструкторы подробно обсуждались в главе 4. Глава 9. Шаблон Abstract Factory 243



Вот тут-то на арене появляется класс туре2туре, уточняющий, что функция Do-Create вызывается функцией Create. Проанализируем следующий фрагмент кода.

код приложения typedef AbstractFactory <

TYPELIST 3(Soldier, Monster, SuperMonster)

>

AbstractEnemyFactory;

В главе 3 было показано, что шаблонный класс AbstractFactory генерирует иерархию классов, показанную на рис. 9.2. Класс AbstractEnemyFactory является потомком классов AbstractFactoryunit<Soldier>, AbstractFactoryUnit<Monster> и AbstractEnemyUnit<superMonster>. В каждом из них определяется чисто виртуальная функция-член Create, так что класс AbstractEnemyFactory обладает тремя перефужен-ными функциями Create. Короче говоря, класс AbstractEnemyFactory практически эквивалентен абсфактному классу с тем же именем, определенному в предьщущем разделе.

AbstractFactoryUnit <Saidier>

AbstractFactoryUnit <SuperMonster>

GenScatterHierarchy <SuperMonster,AbstractFactoryUnit>

GenScatterHlerarcliy <NullType,AbstractFactoryUnit>

AbstractFactoryUnit <Monster>

GenScatterHierarcliy <Monster,AbstractFactoryUnlt>

GenScatterHierarchy <TYPELIST 1(SuperMonster),AbstractFactoryUnit>

GenScatterHierarchy <Soldier,AbstractFactoryUnit>

GenScatterHierarchy <TYPELIST 2(Monster,SuperMonster),AbstractFactoryUnit>

AbstractEnemyFactory

Рис. 9.2. Иерархия классов, генерируемая классом AbstractFactory



Шаблонная функция-член Create из класса AbstractFactory играет роль диспетчера, направляющего запрос на создание объекта соответствующему базовому классу.

AbstractEnemyFactory* р = ...; Monster* pogre = p->Create<Monster>();

Автоматически генерируемая версия класса обладает одним важным преимуществом - класс AbstractEnemyFactory имеет высокий уровень модульности (granularity). Программист может автоматически конвертировать ссылку на объект класса AbstractEnemyFactory в ссылку на объект класса AbstractFactory<Soldier>, AbstractFac-tory<Monster> или AbstractFactory<SuperMonster>. Таким образом, различным частям приложения можно передавать лищь небольшие разделы фабрики. Например, допустим, что некий модуль (Surprises. срр) должен создавать только объекты класса SuperMonster. Этому модулю можно передавать только указатели или ссылки на объекты класса AbstractFactory<SuperMonster>, так что модуль Surpri ses. срр не связан ни с классом Soldier, ни с классом Monster.

Используя модульность класса AbstractFactory, можно сократить количество связей, задействованных в шаблоне проектирования Abstract Factory. Это не снизит степень безопасности интерфейса абстрактной фабрики, поскольку модульным является только интерфейс, а не реализация класса.

Итак, перед нами встает проблема реализации интерфейса. Второе важное преимущество автоматически сгенерированной версии класса AbstractEnemyFactory заключается в том, что его реализация также генерируется автоматически.

9.3. Реализация класса AbstractFactory

Определив интерфейс, перейдем к реализации класса, стремясь сделать это как можно проще.

Поскольку интерфейс использует списки типов, естественно построить обобщенную реализацию класса AbstractFactory с помощью списков типов конкретных изделий. С практической точки зрения реализация класса, соответствующего легкому уровню игры, должна выглядеть следующим образом.

Код приложения typedef ConcreteFactory <

Абстрактная фабрика, подлежащая реализации

AbstractEnemyFactory,

Стратегия создания объектов

(например, с помощью оператора new)

OpNewFactoryunit,

конкретные классы, создаваемые данной фабрикой TYPELIST 3(SillySoldier, SillyMonster, sillySuperMonster)

>

EasyLevelEnemyFactory;

Три аргумента гипотетического (пока) шаблонного класса ConcreteFactory содержат достаточно информации, чтобы полностью реализовать фабрику.

• Класс AbstractEnemyFactory описывает интерфейс абстрактной фабрики, подлежащей реализации, и неявно задает список изделий.

• Класс OpNewFactoryunit представляет собой стратегию, определяющую, каким образом осуществляется фактическое создание объектов.



0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 [ 75 ] 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105