Abstract Factory design pattern

Или с други думи „Фабрика за фабрики“. И тази „фабрика за фабрики“ е под формата на абсклас/интерфейс, който повелява на под-фабриките си какъв тип продукти трябва да произвеждат, а не само един продукт както при Factory Method.

Представяме си един конгломерат (напр. General Motors) от много марки автомобили като Шевролет, Понтиак, Кадилак…

GM налага на отделните си марки, че всички техни коли трябва задължително да имат например 3 неща – двигател, спирачки и климатик.
Но какви конкретно – те си решават.

И ето как се оформят следната основна структура от класове, която задава същността на този design pattern – абсклас/интерфейс GM, който има 3 абсметода createEngine(), createBrakes() и createAirconditioner().
И „под-фабриките“ му – класовете Chevrolet, Pontiac и Cadillac, които трябва да ги имплементират/наследяват.

Какво трябва да има във всяка имплементация на всяка от тези под-фабрики (или concrete factory)? Да създават обекти от други класове – за различните марки двигатели, спирачки и климатици.

Да се върнем на определението: „The Abstract Factory Pattern provides an interface for creating families of related or dependent objects“.
Какви семейства или групи от свързани или зависими обекти? Ако вземем под-фабриката Chevrolet тя какво произвежда? Шевролети ще произвежда разбира се. Какво има във всеки шевролет задължително? Двигател, спирачки и климатик.

Както и Pontiac, и Cadillac… всички отделни марки, които GM произвежда (респективно наследяват/имплементират GM) също трябва да имат поне двигател, спирачки и климатик.

Тези три обекта не са ли „related“ помежду си? Са естествено.

Къде е „interface for creating…“? Kласът GM, който повелява на подфабриките си, че всяка трябва да има винаги поне трите неща.
На шевролета, понтиака или кадилака, какъв ще му е конкретно двигателят, спирачките и климатика – те вече си решават, важното е да не произведат нещо без тези трите неща.

„interface for creating families of related objects“ – това е цялата философия.

Вече отделно за всеки от трите задължителни компонента трябва да си направим отделни йерархии – например клас Engine, който го наследяват класове VolvoPenta, Trabant… клас Brakes, който го наследяват класове…., клас Airconditioner, който го наследяват Carrier, Daikin, Inventor…
Затова се казва също и „…without specifying their concrete classes…“. Демек, не казваш всяка марка какъв конкретен двигател да има, а да има двигател изобщо.

Защо трябва?

За да може в класа GM да зададем, че първият абсметод трябва да връща обект от клас Engine, а не конкретно VolvoPenta (нали казахме, че е важно да имаме двигател, без значение марката).
Съответно вторият, третият и т.н. абсметоди трябва да връщат обекти от клас Brakes и Aircondiotioners…

Разликата с Factory Method e, че там имаш един factory method, който създава един обект. Тук можеш да обединяваш различни factory methods в групи. Точно както заводът за двигатели, спирачки или климатици прави само това, а заводът за шевролети, кадилаци и понтиаци комбинира отделните техни продукти (двигатели, спирачки и климатици).

Eдно голямо предимство и на двата вида Factory Patterns – method и abstract е, че можеш да инджектваш в друг клас цялата „фабрика“ (била тя method или някоя от под-фабриките, concrete factories), вместо да инджектваш готов обект.
Демек, „на ти фабриката, направи си обекта сам“.

Затова и двете – Factory Method и Factory Abstract спадат към т.н. „creational design patterns“, защото и двете предлагат усложнен, но мощен и гъвкав начин за създаване на обекти.

Основното предимство и полза от Abstract design pattern е капсулиране на „производството“ на близки по структура обекти.

А от „близки по структура“ идва и другото му предимство – взаимозаменяемостта им.