Паттерны GoF - Abstract Factory (лекция)
Автор: MiF
<MiF> Поехали, Abstract Factory
<MiF> Назначение - предоставление интерфейса для создания связанных объектов,
скрывая конкретные их классы
<MiF> Нафиг это надо, на примере кривого GUI
<MiF> хотим кучу вариантов формочек, кнопочек, то есть семейств gui-объектов,
такчтобы юзер выбрал подходящий вариант и все работало хорошо
<MiF> то есть есть красивый вариант gui, и не красивый
<MiF> хочется простой выбор сделать
<MiF> Как вкратце делается - делаем абстрактную фабрику GUI-элементов, и две
конкретных, одна производит красивые кнопочки, другая уродские и шустрые
<MiF> Применимость:
<MiF> то есть когда применять :)
<MiF> 1. система не должна знать как создаются и представляются входящие в нее
объекты
<MiF> 2. входящие в семейство объекты должны использоваться вместе, типа с
уродским гуи совмещать красивый нельзя :)
<MiF> 3. хочется спрятать реализацию с глаз долой
<MiF> Диаграммы здесь рисовать нельзя ну и ладно :)
<MiF> Участники:
<MiF> 1. Abstract Factory - объявляет интерфейс для создания абстрактных
продуктов
<MiF> 2. ConcreteFactory - реализует это создание
<MiF> 3. AbstractProduct - объявляет интерфейс для продукта
<MiF> 4. CjncreteProduct - реализует конкретный продукт
<MiF> *Concrete
<MiF> 5. Client - видит AbstractFactory и AbstractProduct, больше ничего не
знает и рад до смерти
<MiF> Отношения:
<MiF> Создается одна нужная ConcreteFactory, пользовтель через интерфейс
AbstractFactory создает конкретные продукты
<MiF> Как результат:
<MiF> 1. изоляция конкретных классов, то есть типов никто не знает, все
работает через интерфейсы, работает LSP
<MiF> 2. замена семейст продуктов делается безболезненно
<MiF> 3. гарантия сочетаемости продуктов
<MiF> Косяки: изменение набора продуктов изменяет интерфейс фабрики
<MiF> Теперь аццкий пример
<MiF> куда код лучше постить короткий?
<MiF> сюда или куда-нибудь в другое место?
<Zeux> сюда наверное
<MiF> короче пример с gui:
<MiF> class IGUIFactory { public: virtual IButton* CreateButton() = 0; virtual
IButton* CreateLabel() = 0; ....}
<MiF> class UglyGUIFactory : public IGUIFactory { public: IButton*
CreateButton() { return new UglyButton(); ....}
<MiF> class CoolGUIFactory : public IGUIFactory { public: IButton*
CreateButton() { return new CoolButton(); ....}
<MiF> и соответсвенно есть CoolButton: public IButton, UglyButton : public
IButton, ....
<MiF> пользовтель видит только интерфесы абстрактной фабрики и всех ее продуктов
<MiF> вот собственно все
<MiF> жду вопросов
<kas> рассказывай как избавляться от тысяч
<kas> функций
<kas> интерфейсныъ
<kas> *х
<MiF> как сделать, что интерфейс абстрактной фабрики не пух?
<kas> ну да
<MiF> *чтобы
<_Winnie> ну то что я вижу, загоняется в шаблон.
<kas> типа CreateWidget ( type )
<CEMEH> У меня более общий вопрос другого плана. Было бы клево, если бы по
каждому паттерну коротенько его применения в геймдеве.
<CEMEH> Все не надо, только классические и нетривиальные.
<kas> виртуальные функции
<MiF> сейчас
<MiF> kas, hint: loki
<MiF> там это обощено списками типов
<MiF> *обощено
<kas> чиво локи, александреску я и так почитать мог :)
<MiF> *обобщено блин
<DaGGeR> lfdfq hfccrfpeq
<_Winnie> template <class GUIElement> struct Gui::ElementFabric { void T
*Create() { return new T; } };
<_Winnie> T -> GUIElement
<kas> панимать, ага
<DaGGeR> гмгмгм
<DaGGeR> готично
<MiF> :)
<_Winnie> можно проще -
<_Winnie> вместо ООП-нотого класса завести указатель на функцию.
<MiF> c-style virtual functions?
<MiF> :)
<_Winnie> template <class T> IButton *CreateButton() { return new T; }
<_Winnie> ну и "фабрека" - это typedef IButton (*TFabric)();
<_Winnie> no clutter, no gay code.
<Sark7> фигасе фабрика
<Sark7> только буттоны делает
<DaGGeR> dbyb ghbvth gjkysq yf 'dthajkk rbym
<DaGGeR> блин
<DaGGeR> Вини, пример полный на эверфол кинь
<MiF> +
<DaGGeR> я по частям плохо воспринимаю
<CEMEH> Значит, следуюший вопрос - почему делают фабрики, а не такие
темплейтные функции? :)
<_Winnie> DaGGeR, полностью -
<_Winnie> "template <class T> IButton *CreateButton() { return new T; }"
<Sark7> потому что надо знать конкретный класс
<Sark7> или я не вижу пойнт
<Sark7> винни
<Zeux> какая-то странная фабрика. Получается, каждый раз я знаю, что конкретно
хочу создать
<CEMEH> Ну хорошо, табличку указателей на функции.
<MiF> йоу
<MiF> люди
<_Winnie> CEMEH, потому что ООП это модно.
<MiF> это AbstractFactory, а не просто Factory
<CEMEH> Нет.
<_Winnie> а указатели на функции, это С а не ООП.
<Sark7> каких табличек?
<Sark7> а, понел
<Sark7> ну, тот же класс
<Sark7> какая разница
<CEMEH> Нет. Не тот же.
<Sark7> почему?
<CEMEH> Потому что класс - это не только поведение.
<CEMEH> Потому что поведение не обязательно stateless.
<_Winnie> ну, и есть ещё тонкость с ковариантным возращаемым типом у
виртуальных функций.
<Sark7> [createcoolbutton, createcoolwindow] или class { createcoolbutton;
createcoolwindow; }
<Sark7> какое поведение у фабрики
<CEMEH> Потому что фабрика не просто вызывает new, если вам угодно.
<Sark7> какое stateless
<_Winnie> в GUI::Fabrict<T>::Create я могу вернуть T* а не IButton*
<Sark7> CEMEH, почему?
<MiF> CEMEH прав, здесь это для примера
<CEMEH> Ну обо всем этом я хотел услышать от аффтара. Когда он опишет
конкретные применения.
<MiF> дык я не аффтар, я рассказчик
<CEMEH> Назову одно. Можно думать о специализированных менеджерах памяти для
разных объектов как о фабрике.
<Sark7> _Winnie, ты можешь сделать new T() и без фабрики, раз знаешь конкретный
класс
<MiF> Вообщем все еще раз посмотрите на результаты
<MiF> Главное: 1. сокрытие конкретных типов, 2. объекты создаются семейством
<kas> непересекающися
<kas> причом
<MiF> именно
<DobroKOT> Sark7, не знаю.
<Sark7> ну, я фабрику все время рассматривал как namespaced new можно сказать
<DobroKOT> Sark7, typedef IButton (*TFabric)();
<DobroKOT> TFabric - это не шаблон.
<MiF> _Winnie, я твоих аргументов не понял
<DobroKOT> и он не знает от T
<CEMEH> 3. Контроль за инициализацией объектов, я бы добавил.
20 января 2006