Zrozum różnice w motywacjach:
Załóżmy, że budujesz narzędzie, w którym masz obiekty i konkretną implementację wzajemnych powiązań obiektów. Ponieważ przewidujesz różnice w obiektach, stworzyłeś pośredniość, przypisując odpowiedzialność za tworzenie wariantów obiektów do innego obiektu ( nazywamy to fabryką abstrakcyjną ). Ta abstrakcja ma dużą zaletę, ponieważ przewiduje się przyszłe rozszerzenia wymagające wariantów tych obiektów.
Inną dość intrygującą motywacją w tej linii myśli jest przypadek, w którym każdy przedmiot z całej grupy będzie miał odpowiedni wariant. W zależności od pewnych warunków, zastosowany zostanie jeden z wariantów, i za każdym razem wszystkie obiekty muszą być tego samego wariantu. Może to być nieco sprzeczne z intuicją, ponieważ często wydaje nam się, że - o ile warianty obiektu są zgodne ze wspólnym jednolitym kontraktem ( interfejs w szerszym znaczeniu ), konkretny kod implementacyjny nigdy nie powinien ulec awarii. Intrygującym faktem jest to, że nie zawsze jest to prawdą, szczególnie gdy oczekiwanego zachowania nie można modelować w umowie programowej.
Prosty ( zapożyczenie pomysłu z GoF ) jest każda aplikacja GUI, która mówi, że wirtualny monitor emuluje wygląd MS, Mac lub Fedory. Tutaj, na przykład, gdy wszystkie obiekty widżetów, takie jak okno, przycisk itp. Mają wariant MS, z wyjątkiem paska przewijania, który pochodzi z wariantu MAC, przeznaczenie narzędzia nie powiedzie się.
Te powyższe przypadki stanowią podstawową potrzebę abstrakcyjnego wzorca fabrycznego .
Z drugiej strony, wyobraź sobie, że piszesz platformę, aby wiele osób mogło zbudować różne narzędzia ( takie jak powyższe przykłady ) za pomocą tej platformy. Zgodnie z ideą frameworku nie musisz tego robić, chociaż nie możesz użyć konkretnych obiektów w swojej logice. Raczej stawiasz kontrakty na wysokim poziomie między różnymi obiektami i sposób ich interakcji. Podczas gdy Ty ( jako programista frameworka ) pozostajesz na bardzo abstrakcyjnym poziomie, każdy budowniczy narzędzia jest zmuszony podążać za twoimi konstrukcjami frameworka. Jednak oni ( twórcy narzędzi ) mają swobodę decydowania, który obiekt ma zostać zbudowany i w jaki sposób wszystkie obiekty, które utworzą, będą oddziaływać. W przeciwieństwie do poprzedniego przypadku ( abstrakcyjnego wzoru fabrycznego ), ty ( jako twórca frameworka)) w tym przypadku nie trzeba pracować z konkretnymi obiektami; i raczej może pozostać na poziomie umownym przedmiotów. Co więcej, w przeciwieństwie do drugiej części poprzednich motywacji, ty lub twórcy narzędzi nigdy nie masz sytuacji mieszania przedmiotów z wariantów. Tutaj, podczas gdy kod frameworka pozostaje na poziomie kontraktu, każdy twórca narzędzi jest ograniczony ( ze względu na naturę samej sprawy ) do używania własnych obiektów. Tworzenie obiektów w tym przypadku jest delegowane do każdego implementatora, a dostawcy ram zapewniają tylko jednolite metody tworzenia i zwracania obiektów. Takie metody są nieuniknione dla programisty frameworka, aby kontynuowały kod i mają specjalną nazwę o nazwie Metoda fabryczna ( Wzorzec metody fabrycznej dla wzorca bazowego ).
Kilka uwag:
- Jeśli znasz „metodę szablonów”, zobaczysz, że metody fabryczne są często wywoływane z metod szablonów w przypadku programów dotyczących dowolnej formy frameworka. Natomiast metody szablonów programów użytkowych są często prostą implementacją określonego algorytmu i pozbawione metod fabrycznych.
- Co więcej, dla kompletności myśli, przy użyciu frameworka ( wspomnianego powyżej ), gdy budowniczy narzędzi buduje narzędzie, w ramach każdej metody fabrycznej, zamiast tworzyć konkretny obiekt, może on / ona dalej przekazać odpowiedzialność streszczeniu - obiekt fabryczny, pod warunkiem, że konstruktor narzędzia przewiduje odmiany konkretnych obiektów dla przyszłych rozszerzeń.
Przykładowy kod:
//Part of framework-code
BoardGame {
Board createBoard() //factory method. Default implementation can be provided as well
Piece createPiece() //factory method
startGame(){ //template method
Board borad = createBoard()
Piece piece = createPiece()
initState(board, piece)
}
}
//Part of Tool-builder code
Ludo inherits BoardGame {
Board createBoard(){ //overriding of factory method
//Option A: return new LudoBoard() //Lodu knows object creation
//Option B: return LudoFactory.createBoard() //Lodu asks AbstractFacory
}
….
}
//Part of Tool-builder code
Chess inherits BoardGame {
Board createBoard(){ //overriding of factory method
//return a Chess board
}
….
}