Dzisiaj kilka słów w zasadzie o dwóch wzorcach, Factory i Abstract Factory. Oba wzorce należą do grupy wzorców kreacyjnych i pomagają w zarządzaniu i organizacji kodu, zwłaszcza gdy mamy do czynienia z rozbudowanymi strukturami obiektów.
Factory
Wzorzec Factory jest używany do tworzenia obiektów z jednej rodziny produktów. Pozwala na utworzenie obiektu bez konieczności specyfikowania dokładnej klasy, która ma być utworzona.
Wyobraźmy sobie, że będziemy potrzebowali wielu obiektów różnych zwierząt (np. pies, kot, małpa, koń). Wszystkie zwierzęta są osobnymi klasami ale mają wiele wspólnych cech więc możemy wyodrębnić je w interface.
interface Animal {
name: string;
eat(): string;
sleep(): string;
run(): string;
}Każde zwierzę ma imię oraz 3 metody, może jeść, spać i biegać. Ale to tylko interface, pusta wydmuszka klasy, nadal nie wiemy jak te metody wyglądają. To właśnie musimy definiować w klasach.
class Dog implements Animal {
name: string;
constructor(name: string) {
this.name = name;
}
eat(): string {
return `Dog ${name} is eating`;
}
sleep(): string {
return `Dog ${name} is sleeping`;
}
run(): string {
return `Dog ${name} is running`;
}
}class Cat implements Animal {
name: string;
constructor(name: string) {
this.name = name;
}
eat(): string {
return `Cat ${name} is eating`;
}
sleep(): string {
return `Cat ${name} is sleeping`;
}
run(): string {
return `Cat ${name} is running`;
}
}Kiedy mamy już klasy zwierząt przechodzimy do stworzenia samej Fabryki. Skorzystamy ze wzorca tworząc schronisko. Mamy klasę schroniska która zawiera abstrakcyjną metodę addAnimal. Klasy DogsShelter oraz CatsShelter dziedziczą po tej klasie więc będą musiały tą metodę zaimplementować.
class Shelter {
public abstract addAnimal(name: string): Animal;
}
class DogsShelter extends Shelter {
public addAnimal(name: string): Dog{
return new Dog(name);
}
}
class CatsShelter extends Shelter {
public addAnimal(name: string): Cat{
return new Cat(name);
}
}Co nam to daje ?
Załóżmy, że klasa Shelter ma inne metody niekoniecznie abstrakcyjne. Wtedy wszystkie klasy dziedziczące mogą z nich korzystać i nie musimy ich implementować. Albo w innym przykładzie, mamy klasę Button czyli przycisk. Każdy widok aplikacji ma inny styl przycisków ale niezależnie od tego przycisk jest w każdym widoku i pełni taką samą funkcję. Każdy widok implementuje swoją „Fabrykę” przycisków ale nie musimy już każdego z nich definiować z osobna.
Abstract Factory
Nie przepadam za rozróżnianiem Abstract Factory jako oddzielny wzorzec, wprowadza to dla mnie zbędną komplikację. Ja rozróżniam to najprościej jak się da czyli, Factory method to metoda wewnątrz klasy która wytwarza uniwersalny obiekt. Natomiast Abstract Factory potrzebujemy wtedy kiedy liczba różnych obiektów które trzeba stworzyć rośnie. Kiedy nie chcemy mieć już tylko klasy Button ale i Form, Checkbox i Link wtedy te metody po prostu wrzucamy do jednej abstrakcyjnej klasy. Wtedy ta klasa jest odpowiedzialna za tworzenie tych obiektów, czyli przekazaliśmy tą odpowiedzialność, tym samym upraszczając naszą klasę główną.
