Fabryka abstrakcyjna, Fabryka abstrakcji, Abstract factory

Uzasadnienie stosowania:

Jedna metoda fabrykująca tworzy obiekty implementujące jeden interfejs. Dodając do polimorficznej wersji kolejne metody fabrykujące otrzymujemy fabrykę abstrakcyjną, zdolną do tworzenia obiektów implementujących różne interfejsy. Tworząc konkretną fabrykę decydujemy tylko raz o typach wszystkich konkretnych implementacji (muszą więc one być ze sobą sensownie powiązane). Nie musimy podejmować osobnych decyzji dla każdego interfejsu (było by to konieczne przy użyciu kilku osobnych Metod fabrykujących zamiast jednej fabryki).

Intencja

Dostarcza możliwość tworzenia rodzin zależnych lub spokrewnionych obiektów bez opisywania konkretnych klas.

Motywacja

Załóżmy, że dostarczamy narzędzia do budowy interfejsu użytkownika, w którym użytkownik może zmieniać jego wygląd pomiędzy kilkoma standardami, np. Windows i RedHat Linux

Programowanie aplikacji powinno być niezależne od wyglądu, aby mogło być przenaszalne i łatwo rozszerzalne.

Stosowalność:

Gdy chcemy się uniezależnić od złożonego API. Obudowując zewnętrzne API systemu wrapperami (wzorzec Most) możemy stworzyć rodzinę implementacji różnych interfejsów która będzie odpowiadała za komunikację z danym nam API. Dodając obsługę nowego API do systemu dodajemy po jednej implementacji do ka?dego interfejsu i jedną konkretną fabrykę. W jednym tylko miejscu kodu decydujemy jakiego interfejsu chcemy użyć poprzez stworzenie jednej z konkretnych fabryk.

Przykładowy kod

public abstract class Okno { /*...*/ }
public abstract class Suwak{ /*...*/ }
public abstract class SystemOkien {
	public abstract Okno utworzOkno();
	public abstract Suwak utworzSuwak();
} 
public class WindowsOkno extends Okno { /*def Okna w systemie Windows*/ }
public class WindowsSuwak extends Suwak { /*def Suwaka w systemie Windows*/ } 
public class WindowsSystem extends SystemOkien {
	public Okno utworzOkno() { 
		return new WindowsOkno();
		}
	public Suwak utworzSuwak() {
		return new WindowsSuwak();
 	} 
}
public class RedHatOkno extends Okno { /*def Okna w systemie RedHat*/ }
public class RedHatSuwak extends Suwak { /*def Suwaka w systemie RedHat*/ }  
public class RedHatSystem extends SystemOkien {/*analogicznie do WindowsOkna*/}

Uzycie:
Tworze nowa metode a w niej warunki - jezeli parametr = windows to generuje nowy obiekt new WidowsSystem i tak dalej (jak w Fabryce). Rozwiazujemy nasz problem przez zdefiniowanie abstrakcyjnej klasy SystemOkien, która dostarcza interfejs do kreowania roznych rodzajow narzedzi (tutaj okno, suwak). Dla każdego rodzaju narzędzia (okna, suwaka) istnieje również klasa abstrakcyjna, której konkretne podklasy implementuja narzędzia dla określonego już wygladu. SystemOkien posiada metody zwracające obiekt dla każdej abstrakcyjnej klasy narzedzi. Klient wywoluje te metody nie wiedzac, z której konkretnie klasy korzysta.

Przykładowy diagram

Struktura Fabryki Abstrakcyjnej

Zobacz przykład Zobacz przykład

Elementy Fabryki Abstrakcyjnej

  • FabrykaAbstrakcyjna (SystemOkien)
    Deklaruje interfejs dla operacji, które tworzą obiekty AbstrakcyjnyProdukt
  • KonkretnaFabryka (WindowsSystem, RedHatSystem)
    Implementuje operacje do tworzenia obiektów KonkretnyProdukt
  • AbstrakcyjnyProdukt (okno, suwak)
    Deklaruje interfejs dla typu produktu
  • KonkretnyProdukt (WindowsOkno, WindowsSuwak, itd.)
    Implementuje interfejs AbstrakcyjnyProdukt
  • Klient
    Używa tylko interfejsów FabrykaAbstrakcyjna i AbstrakcyjnyProdukt

Konsekwencje

Izoluje konkretne klasy.
Ułatwia wymianę rodzin produktów