Абстрактная фабрика - паттерн, порождающий объекты. Известен также под именем Kit (инструментарий).
Абстрактная фабрика - это код, который решает, какой из множества подклассов должен использоваться в данный момент.
Исходный код запрашивает экземпляр класса. Данный класс возвращает экземпляр подкласса, который наиболее соответствует условиям. Подобный класс называют абстрактной фабрикой. Допустим, мы имеем дело с базой данных. В этом случае, абстрактная фабрика будет возвращать объект, который подходит для работы с конкретной базой данных. При этом, все подклассы имеют одинаковый API.
Perl DBI - это отличный пример абстрактной фабрики. Каждый раз, при вызове connect, фабрика ожидает, что ей будет передан тип базы данных, с которой предстоит работать. В зависимости от типа БД она будет подгружать DBD. При этом, всегда можно добавить новые драйвера баз данных, и для начала их
использования не потребуется переписывать код системы.
Пример:
|
1 2 |
use DBI; my $dbh = DBI->connect("dbi:mysql:dbname:localhost", "user", "password"); |
После подключения к БД и получения дескриптора $dbh, можно обращаться к базе данных, не размышляя о том, какого она типа. Если вы решите переехать с mysql на oracle, придется изменить только название драйвера в строке connect. Большая часть кода останется неизменной.
Кроме того, отличной демонстрацией работы Abstract Factory являются системы виджетов. Все виджеты могут реализовывать разную функциональность. Один выводит форму для голосований, другой - рекламный баннер, и т.п. Для того, чтобы подключение нового виджета было быстрым и безболезненным, можно использовать шаблон Abstract Factory.
Допустим, имеется список виджетов, которые требуется отобразить на сайте. Создаем абстрактный класс WidgetFactory, который в зависимости от параметров, создает объект конкретного подкласса. Можно даже добавить типизацию виджетов. Тогда для каждого типа виджета можно создать собственную абстрактную фабрику, которая обращается к своим конкретным подклассам.
Очень простой пример Abstract Factory
System/ASystem1.pm :
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
package System::ASystem1; use strict; sub new { my $type=shift; my $self; $self = bless( {}, $type); return $self; } sub process { my $self = shift; my $time = localtime(); print "Make test\nShow time: $time\nProcess done\n"; return 1; } 1; |
System/ASystem2.pm :
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
package System::ASystem2; use strict; sub new { my $type=shift; my $self; $self = bless( {}, $type); return $self; } sub process { my $self = shift; print "Process done\n"; return 1; } 1; |
Фабрика имеет только один метод, который возвращает вызываемый тип объекта. Передаваемые данные она использует для определения нужного класса и модуля.
AbstractFactory.pm :
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
package AbstractFactory; use strict; sub create { my $class = shift; my $requested_type = shift; my $location = "System/$requested_type.pm"; my $class = "System::$requested_type"; require $location; return $class->new(@_); } 1; |
В зависимости от требований разработчика, будет подключена та или иная система.
abstractfactory.pl :
|
1 2 3 4 5 6 7 8 9 10 11 12 |
#!/usr/bin/perl use strict; use AbstractFactory; my $handler1 = AbstractFactory->create("ASystem1"); $handler1->process(); my $handler2 = AbstractFactory->create("ASystem2"); $handler2->process(); exit; |
Никогда не использовал абстрактную фабрику, и представить ее применение вообще не особо мог - если не могу представить зачем она мне может потребоваться, то ИМХО и думать об таком шаблоне не надо :). Примеры типа того, что был у Вас с виджетами я, конечно, себе представлял, но мне это не надо :)
У Гаммы в книге описан похожий пример и еще пример с реализацией похожих компонентов для разных архитектур - но все это требуется небольшому числу программистов и очень редко. Кроме того, если бы мне пришлось реализовывать один и тот же компонент по-разному для различных архитектур - я бы однозначно и запилил бы что-то типа фабрики, а как иначе?
У Вас очень понравился пример с БД, я, признаться, в таком направлении не думал. Кажется, можно найти еще какие-то аналогии. Я подумаю, спасибо Вам )
Владимир, абсолютна согласна с вашей фразой "мне это не надо" :) Действительно, большинству это не нужно. Особенно, web-разработчикам. Другая специфика работы.
Я иногда разбираю паттерны просто для развития мозгов. Решишь такую задачку и начинаешь чувствовать просветление :) Но обычно до паттернов не доходит - времени надо много на разбор, а его нет - есть более приоритетные задачи.
С паттернами у меня выходит так, что по ходу работы иногда получается красивое решение. И вот в этот момент, понимаешь, что по-любому это кто-то придумал до тебя. Открываешь книжки, и читаешь все недостатки своего решения, способы его улучшить и прочее в описании какого-нибудь паттерна :).
Я тут по совместительству веду в ВУЗе технологию программирования, и по программе я должен бы дать студентам паттерны. Но я ведь знаю, что без обширных и хороших примеров они не запомнятся. По абстрактной фабрике был такой момент... после того, как студентам на лекциях рассказывали этот паттерн, у них появлялось невероятное желание применять его всюду и они в свои примитивные лабораторные впиливали по 2-5 фабрик (там, где они вообще не нужны были).
Мораль такова, что у некоторых шаблонов действительно очень красивое и элегантное решение, у многих появляется желание использовать эти шаблоны, но надо четко указывать какие проблемы решает эти паттерны ("элегантное решение чего?"). Я стараюсь делать на этом акцент и на занятиях со студентами и в своих статьях.
Natalie >> Я иногда разбираю паттерны просто для развития мозгов
Не так давно, нашел книжку очень интересную:
Джейсон Мак-Колм Смит «Элементарные шаблоны проектирования» : Пер. с англ. — М. : ООО “И.Д. Вильямс”, 2013. — 304 с.
Очень рекомендую для развития мозгов. В плане паттернов там есть обширный матан.
Спасибо за книгу!!! Я не знала, что есть такая. Классическая книга GoF мне не очень нравится. Была от Влиссидеса, кажется, но она мне показалась вообще невнятной.