Fabryka Abstrakcyjna (Abstract Factory) to jeden z kluczowych wzorców kreacyjnych, który pozwala tworzyć rodziny spokrewnionych ze sobą obiektów bez konieczności określania ich konkretnych klas. Zamiast definiować poszczególne typy obiektów bezpośrednio w kodzie, wzorzec Fabryki Abstrakcyjnej udostępnia interfejs do tworzenia "produktów" należących do różnych "rodzin", czego rezultat można uzyskać bez konieczności definiowania z góry, jakich konkretnych klas dotyczą te rodziny.
Problem
Załóżmy, że pracujesz nad aplikacją, która będzie działać na różnych systemach operacyjnych: Windows oraz macOS. Każdy z tych systemów operacyjnych ma swoje specyficzne elementy interfejsu użytkownika, jak Okna i Przyciski. Chcemy, aby tworzenie tych elementów było elastyczne i niezależne od konkretnej platformy.
Przykład:
System interfejsów użytkownika posiadający fabryki dla różnych systemów operacyjnych:
- Windows: Fabryka dla systemu Windows tworzy elementy OknoWindows i PrzyciskWindows.
- macOS: Fabryka dla macOS tworzy analogicznie elementy OknoMac i PrzyciskMac.
Rozwiązanie
Wzorzec Fabryki Abstrakcyjnej proponuje stworzenie zestawu interfejsów dla każdej rodziny spokrewnionych obiektów oraz zapewnienie metod kreacyjnych, które będą używane do tworzenia tych obiektów.
Definicja Interfejsów Produktów
Na początek definiujemy wspólne interfejsy dla produktów w danej rodzinie:
interface Okno {
void renderuj();
}interface Przycisk {
void kliknij();
}
Definicja Fabryk Abstrakcyjnych
Następnie definiujemy interfejs fabryki abstrakcyjnej:
interface FabrykaUI {
Okno stworzOkno();
Przycisk stworzPrzycisk();
}
Implementacja Fabryk Konkretnych dla Każdego Systemu Operacyjnego
Tworzymy konkretne klasy fabryk dla systemów Windows i macOS:
class FabrykaWindows implements FabrykaUI {
@Override
public Okno stworzOkno() {
return new OknoWindows();
}@Override
public Przycisk stworzPrzycisk() {
return new PrzyciskWindows();
}
}class FabrykaMac implements FabrykaUI {
@Override
public Okno stworzOkno() {
return new OknoMac();
}@Override
public Przycisk stworzPrzycisk() {
return new PrzyciskMac();
}
}
Implementacja Konkretnego Produktu
Konkretne implementacje produktów, czyli okien i przycisków na obu systemach:
class OknoWindows implements Okno {
@Override
public void renderuj() {
System.out.println("Renderowanie okna w stylu Windows");
}
}class PrzyciskWindows implements Przycisk {
@Override
public void kliknij() {
System.out.println("Kliknij przycisk w stylu Windows");
}
}class OknoMac implements Okno {
@Override
public void renderuj() {
System.out.println("Renderowanie okna w stylu macOS");
}
}class PrzyciskMac implements Przycisk {
@Override
public void kliknij() {
System.out.println("Kliknij przycisk w stylu macOS");
}
}
Korzystanie z Fabryk
Kod klienta używający fabryki do tworzenia elementów interfejsu:
public class Aplikacja {
private FabrykaUI fabrykaUI;public Aplikacja(FabrykaUI fabrykaUI) {
this.fabrykaUI = fabrykaUI;
}public void uruchom() {
Okno okno = fabrykaUI.stworzOkno();
Przycisk przycisk = fabrykaUI.stworzPrzycisk();
okno.renderuj();
przycisk.kliknij();
}public static void main(String[] args) {
FabrykaUI fabryka = new FabrykaWindows(); // Zmiana zależnie od systemu
Aplikacja app = new Aplikacja(fabryka);
app.uruchom();
}
}
Podsumowanie
Wzorzec Fabryki Abstrakcyjnej umożliwia stworzenie segmentów kodu niezależnych od konkretnych klas obiektów, jednocześnie zmniejszając sprzężenie aplikacji z szczegółami implementacyjnymi. Dzięki temu możemy:
- Tworzyć objekty należące do różnych "rodzin" bez konieczności określania ich konkretnych klas.
- Dodawać nowe rodziny produktów bez modyfikowania istniejącego kodu klienta.
Fabryka Abstrakcyjna zapewnia elastyczność i modułowość, dzięki czemu kod jest bardziej przejrzysty i łatwiejszy do utrzymania.