Wzory projektowe: Fabryka kontra metoda fabryczna kontra fabryka abstrakcyjna

183

Czytałem wzorce projektowe ze strony internetowej

Tam czytałem o Fabryce, metodzie Fabryki i fabryce Abstrakcji, ale są one tak mylące, że nie mam jasności w definicji. Zgodnie z definicjami

Fabryka - Tworzy obiekty bez ujawniania logiki tworzenia instancji klientowi i odnosi się do nowo utworzonego obiektu za pośrednictwem wspólnego interfejsu. Jest uproszczoną wersją metody fabrycznej

Metoda fabryczna - definiuje interfejs do tworzenia obiektów, ale pozwala podklasom decydować, którą klasę utworzyć i odwołuje się do nowo utworzonego obiektu za pośrednictwem wspólnego interfejsu.

Fabryka abstrakcyjna - oferuje interfejs do tworzenia rodziny powiązanych obiektów, bez wyraźnego określania ich klas.

Patrzyłem też na inne wątki związane z przepływem stosów dotyczące metody Fabryka abstrakcyjna kontra Fabryka, ale narysowane tam diagramy UML jeszcze bardziej pogarszają moje rozumienie.

Czy ktoś może mi powiedzieć

  1. Czym różnią się te trzy wzorce?
  2. Kiedy stosować który?
  3. A także, jeśli to możliwe, jakieś przykłady Java związane z tymi wzorcami?
Just_another_developer
źródło
3
Kiedy szukałem odpowiedzi na mniej więcej to samo pytanie co OP, znalazłem ten artykuł: From No Factory to Factory Method . Zapewnia wgląd, śledząc ewolucję przykładowego projektu (metoda fabryczna wymieniona w tytule jest jednym z etapów ewolucyjnych).
Nick Alexeev

Odpowiedzi:

251

Wszystkie trzy typy Factory robią to samo: są „inteligentnym konstruktorem”.

Powiedzmy, że chcesz mieć możliwość stworzenia dwóch rodzajów owoców: jabłka i pomarańczy.

Fabryka

Fabryka jest „naprawiona”, ponieważ masz tylko jedną implementację bez podklas. W takim przypadku będziesz mieć taką klasę:

class FruitFactory {

  public Apple makeApple() {
    // Code for creating an Apple here.
  }

  public Orange makeOrange() {
    // Code for creating an orange here.
  }

}

Przypadek użycia: Konstruowanie jabłka lub pomarańczy jest nieco zbyt skomplikowane, aby poradzić sobie z nimi w konstruktorze.

Metoda fabryczna

Metodę fabryczną stosuje się na ogół, gdy masz jakieś ogólne przetwarzanie w klasie, ale chcesz zmienić, jakiego rodzaju owoców faktycznie używasz. Więc:

abstract class FruitPicker {

  protected abstract Fruit makeFruit();

  public void pickFruit() {
    private final Fruit f = makeFruit(); // The fruit we will work on..
    <bla bla bla>
  }
}

... możesz ponownie użyć wspólnej funkcji FruitPicker.pickFruit(), wdrażając fabryczną metodę w podklasach:

class OrangePicker extends FruitPicker {

  @Override
  protected Fruit makeFruit() {
    return new Orange();
  }
}

Fabryka abstrakcyjna

Fabryka abstrakcyjna jest zwykle używana do takich rzeczy jak wstrzykiwanie zależności / strategia, gdy chcesz być w stanie stworzyć całą rodzinę obiektów, które muszą być „tego samego rodzaju” i mieć pewne wspólne klasy podstawowe. Oto niejasny przykład związany z owocami. Przypadek użycia tutaj polega na tym, że chcemy się upewnić, że przypadkowo nie użyjemy OrangePicker na Apple. Dopóki otrzymamy nasz Fruit and Picker z tej samej fabryki, będą do siebie pasować.

interface PlantFactory {

  Plant makePlant();

  Picker makePicker(); 

}

public class AppleFactory implements PlantFactory {
  Plant makePlant() {
    return new Apple();
  }

  Picker makePicker() {
    return new ApplePicker();
  }
}

public class OrangeFactory implements PlantFactory {
  Plant makePlant() {
    return new Orange();
  }

  Picker makePicker() {
    return new OrangePicker();
  }
}
Anders Johansen
źródło
8
+1 To jest odpowiedź najbardziej podobna do mojego zrozumienia tych wzorców. Dodanie przykładów kodu wywołującego (klienta) również by pomogło? Pytanie, które mnie bardzo niepokoi, to: czy możemy powiedzieć, że abstrakcyjny wzorzec fabryczny jest po prostu rozszerzony fabrycznie o fabryczny wzorzec metody (jeśli to prawda, mam jasność na ten temat)?
croraf
9
Oto przykład, którego szukałem od lat.
Taztingo
To fantastyczne wytłumaczenie! Dzięki!
André Andrade
@ AndréAndrade Jak wywołać metodę fabryczną ? Mały kod samle pls :) To rozwiała moje wątpliwości co do jego użycia
Arnab Dutta
25
  1. Czym różnią się te trzy wzorce?

Fabryka: Tworzy obiekty bez ujawniania klientowi logiki tworzenia instancji.

Metoda fabryczna: Zdefiniuj interfejs do tworzenia obiektu, ale pozwól, aby podklasy zdecydowały, którą klasę utworzyć. Metoda Factory pozwala klasie odroczyć tworzenie instancji do podklas

Fabryka abstrakcyjna: zapewnia interfejs do tworzenia rodzin powiązanych lub zależnych obiektów bez określania ich konkretnych klas.

Wzorzec AbstractFactory używa kompozycji do delegowania odpowiedzialności za tworzenie obiektu do innej klasy, podczas gdy wzorzec projektowania metody Factory wykorzystuje dziedziczenie i do tworzenia obiektu korzysta z pochodnej klasy lub podklasy

  1. Kiedy stosować który?

Fabryka: Klient potrzebuje tylko klasy i nie dba o to, jaką konkretną implementację otrzymuje.

Metoda fabryczna: Klient nie wie, jakie konkretne klasy będzie musiał utworzyć w czasie wykonywania, ale chce tylko uzyskać klasę, która wykona zadanie.

AbstactFactory: Gdy system musi utworzyć wiele rodzin produktów lub chcesz udostępnić bibliotekę produktów bez ujawniania szczegółów implementacji.

Abstrakcyjne klasy Factory są często implementowane przy użyciu metody Factory. Metody fabryczne są zwykle wywoływane w ramach metod szablonów.

  1. A także, jeśli to możliwe, jakieś przykłady Java związane z tymi wzorcami?

Factory and FactoryMethod

Zamiar:

Zdefiniuj interfejs do tworzenia obiektu, ale pozwól, aby podklasy zdecydowały, którą klasę utworzyć. Metoda fabryczna pozwala klasie odroczyć tworzenie instancji do podklas.

Diagram UML :

wprowadź opis zdjęcia tutaj

Produkt: Definiuje interfejs obiektów tworzonych przez metodę Factory.

ConcreteProduct: Implementuje interfejs produktu

Twórca: Deklaruje metodę Factory

ConcreateCreator: implementuje metodę Factory w celu zwrócenia instancji ConcreteProduct

Stwierdzenie problemu: Utwórz fabrykę gier, korzystając z metod fabrycznych, które definiują interfejs gry.

Fragment kodu:

Wzór fabryczny. Kiedy stosować metody fabryczne?

Porównanie z innymi wzorami kreacyjnymi:

  1. Projektowanie zaczyna się od metody fabrycznej (mniej skomplikowane, bardziej konfigurowalne, podklasy rozprzestrzeniają się) i ewoluuje w kierunku fabryki abstrakcyjnej, prototypu lub konstruktora (bardziej elastyczny, bardziej złożony), gdy projektant odkrywa, gdzie potrzebna jest większa elastyczność

  2. Abstrakcyjne klasy Factory są często implementowane za pomocą metod fabrycznych , ale można je również zaimplementować przy użyciu Prototype

Odniesienia do dalszej lektury: Wzory projektowania zaopatrzenia

Ravindra babu
źródło
Czy w metodzie fabrycznej nie powinno być zdefiniowane nadklasy?
Tony Lin,
21

Factory - Oddzielna klasa Factory do tworzenia złożonych obiektów.

Przykład: klasa FruitFactory do tworzenia obiektu Fruit

class FruitFactory{

public static Fruit getFruit(){...}

}

Metoda fabryczna - Zamiast całej oddzielnej klasy dla fabryki, po prostu dodaj jedną metodę w tej klasie jako fabrykę.

Dawny:

Calendar.getInstance() (Java's Calendar)

Metoda Fabryki Abstrakcyjnej - Fabryka Fabryki

Np .: Powiedzmy, że chcemy zbudować fabrykę części komputerowych. Istnieje kilka rodzajów komputerów, takich jak laptop, komputer stacjonarny, serwer.

Dlatego dla każdego typu kompresora potrzebujemy fabryki. Dlatego tworzymy jedną fabrykę na wysokim poziomie, taką jak poniżej

ComputerTypeAbstractFactory.getComputerPartFactory(String computerType) ---> This will return PartFactory which can be one of these ServerPartFactory, LaptopPartFactory, DesktopPartFactory.

Teraz te 3 same są znowu fabrykami. (Będziesz miał do czynienia z samym PartFactory, ale pod maską będzie osobna implementacja oparta na tym, co podałeś w fabryce abstrakcyjnej)

  Interface-> PartFactory. getComputerPart(String s), 
Implementations -> ServerPartFactory, LaptopPartFactory, DesktopPartFactory.

Usage:
new ComputerTypeAbstractFactory().getFactory(“Laptop”).getComputerPart(“RAM”)

EDYCJA: edytowane w celu zapewnienia dokładnych interfejsów dla Abstract Factory zgodnie z zastrzeżeniami w komentarzach.

Ravi K
źródło
1
Chodzi o ComputerFactoryto, że masz wspólny interfejs tworzenia ( getScreen(); getKeyboard(); getDiskdrive(); ...), a nie interfejs według typu komputera, jak sugerujesz. Możesz poczuć problem projektowy, jeśli użyjesz tego samego słowa dwa razy w tym samym oświadczeniu: Laptop Factory.get Laptop Part ().
xtofl
Nie, nie, nie, nie używaj samego kodu. To była tylko anologia do zrozumienia. Jeśli chcesz dokładny przykład z interfejsami, oto jest. Obiekty: Interfejs -> ComputerPart, Implementacja -> RAM, HDD, Fabryka procesorów: Interfejs-> PartFactory. getComputerPart (String), Implementacje -> ServerPartFactory, LaptopPartFactory, DesktopPartFactory. Fabryka abstrakcyjna: ComputerType.getPartFactory („String s”) Zastosowanie: nowy ComputerType (). GetFactory („Laptop”). GetComputerPart („RAM”)
Ravi K
2
Zaktualizowałem odpowiedź, aby zająć się twoją obawą. W rzeczywistości abstrakcyjna fabryka to tylko fabryka. Podałem wcześniej przykład wyłącznie w celach informacyjnych (zakładając, że czytelnicy zajmą się interfejsami podczas faktycznej implementacji). Wciąż dziękuję za powiadomienie. Zawsze dobrze jest poprawić. :)
Ravi K
Nie, abstract Factorynie jest fabryką fabryki ... Jest to abstract classlub jest w interfacestanie stworzyć obiekt, który zostanie wdrożony / rozszerzony o różne konkretne fabryki. Szczegółowe informacje na temat kodu znajdują się w zaakceptowanej odpowiedzi. I proszę odpowiednio usunąć lub edytować swoją odpowiedź.
Julien__
Podoba mi się wyjaśnienie metody fabrycznej, która jest wystarczająco zwięzła, aby odsłonić, dlaczego jest tak nazwana. Według tego wzorca fabryka jest metodą, a NIE klasą, która zasadniczo nie jest metodami tworzenia instancji grupujących pomocnika, ale ma znaczenie sama w sobie. Inne bardziej wyszukane odpowiedzi niestety pominęły ten punkt.
wlnirvana
11

Każdy wzorzec projektu rozwija się, aby zapewnić, że nie zostanie zmieniony napisany, działający kod. Wszyscy wiemy, że po dotknięciu działającego kodu pojawiają się defekty w istniejących przepływach roboczych i należy wykonać znacznie więcej testów, aby upewnić się, że niczego nie zepsuliśmy.

Wzorzec fabryczny tworzy obiekty na podstawie kryteriów wejściowych, zapewniając w ten sposób, że nie musisz pisać kodu, jeśli to utworzy ten obiekt, inaczej ten obiekt. Dobrym tego przykładem jest witryna turystyczna. Witryna turystyczna może oferować wyłącznie podróże (lot, pociąg, autobus) lub / i zapewnia hotele lub / i zapewnia pakiety atrakcji turystycznych. Teraz, gdy użytkownik wybierze następny, strona internetowa musi zdecydować, jakie obiekty musi stworzyć. Powinien to również tworzyć obiekt podróży lub hotelu.

Teraz, jeśli planujesz dodanie innej witryny do swojego portfela i uważasz, że można użyć tego samego rdzenia, na przykład strony carpoolingu, która teraz szuka taksówek i dokonuje płatności online, możesz skorzystać z abstrakcyjnej fabryki u podstawy. W ten sposób możesz po prostu zatrzasnąć się w jeszcze jednej fabryce kabin i wspólnych samochodów.

Obie fabryki nie mają ze sobą nic wspólnego, więc jest to dobry projekt, aby trzymać je w różnych fabrykach.

Mam nadzieję, że teraz jest to jasne. Ponownie zapoznaj się z witryną, pamiętając o tym przykładzie, miejmy nadzieję, że to pomoże. I naprawdę mam nadzieję, że poprawnie przedstawiłem wzory :).

Siddharth
źródło
3

Aby uzyskać tę odpowiedź, odsyłam do książki „Gang czterech”.

Istnieją żadne „Fabryka”, ani „Simple fabryczne” ani „Wirtualna Fabryka” definicje zawarte w książce. Zwykle, gdy ludzie mówią o wzorcu „fabrycznym”, mogą mówić o czymś, co tworzy określony obiekt klasy (ale nie wzorzec „konstruktora”); oni mogą lub nie mogą odnosić się do „Factory Method” lub „Abstract Factory” wzorów. Każdy może wdrożyć „Fabrykę” tak, jak tego nie zrobi, ponieważ nie jest to termin formalny (pamiętaj, że niektóre osoby / firmy \ społeczności mogą mieć własne słownictwo).

Książka zawiera tylko definicje „Fabryki abstrakcyjnej” i „Metody fabrycznej”.

Oto definicje z książki i krótkie wyjaśnienie, dlaczego oba mogą być tak mylące. Pomijam przykłady kodu, ponieważ można je znaleźć w innych odpowiedziach:

Metoda fabryczna (GOF) : Zdefiniuj interfejs do tworzenia obiektu, ale pozwól, aby podklasy zdecydowały, którą klasę utworzyć. Metoda fabryczna pozwala klasie odroczyć tworzenie instancji do podklas.

Fabryka abstrakcyjna (GOF) : zapewnia interfejs do tworzenia rodzin powiązanych lub zależnych obiektów bez określania ich konkretnych klas.

Źródło zamieszania : Często można nazwać klasę używaną we wzorcu „Factory Method” jako „Factory”. Ta klasa jest z definicji abstrakcyjna. Dlatego łatwo nazwać tę klasę „Fabryką abstrakcyjną”. Ale to tylko nazwa klasy; nie należy mylić go ze wzorem „Abstract Factory” (nazwa klasy! = nazwa wzoru). Wzór „Fabryki abstrakcyjnej” jest inny - nie używa klasy abstrakcyjnej; definiuje interfejs (niekoniecznie interfejs języka programowania) do tworzenia części większego obiektu lub obiektów, które są ze sobą powiązane lub muszą zostać utworzone w określony sposób.

Pavel Sapehin
źródło
2
AbstractProductA, A1 and A2 both implementing the AbstractProductA
AbstractProductB, B1 and B2 both implementing the AbstractProductB

interface Factory {
    AbstractProductA getProductA(); //Factory Method - generate A1/A2
}

Metodą fabryczną użytkownik może utworzyć A1 lub A2 produktu AbstractProductA.

interface AbstractFactory {
    AbstractProductA getProductA(); //Factory Method
    AbstractProductB getProductB(); //Factory Method
}

Ale Abstract Factory ma więcej niż 1 metodę fabryczną (np. 2 metody fabryczne), używając tych metod fabrycznych stworzy zestaw obiektów / powiązanych obiektów. Korzystając z Abstract Factory, użytkownik może tworzyć obiekty A1, B1 z AbstractProductA, AbstractProductB

rameshvanka
źródło
0

Nikt nie zacytował oryginalnej książki Design Patterns: Elements of Reusable Object-Oriented Software , która daje odpowiedź w dwóch pierwszych akapitach sekcji „Omówienie wzorów kreacyjnych” (moje podkreślenie):

Istnieją dwa typowe sposoby parametryzacji systemu według klas tworzonych przez niego obiektów. Jednym ze sposobów jest podklasowanie klasy, która tworzy obiekty; odpowiada to zastosowaniu wzorca Factory Method (107). Główną wadą tego podejścia jest to, że może wymagać nowej podklasy, aby zmienić klasę produktu. Takie zmiany mogą się kaskadowo. Na przykład, gdy twórca produktu sam jest tworzony metodą fabryczną, musisz również zastąpić jego twórcę.

Inny sposób parametryzacji systemu polega bardziej na składzie obiektu : zdefiniuj obiekt odpowiedzialny za znajomość klasy obiektów produktu i ustaw go jako parametr systemu. Jest to kluczowy aspekt wzorów Abstract Factory (87), Builder (97) i Prototype (117). Wszystkie trzy obejmują stworzenie nowego „obiektu fabrycznego”, którego zadaniem jest tworzenie obiektów produktu. Abstract Factory ma obiekt fabryczny wytwarzający obiekty kilku klas. Konstruktor ma obiekt fabryczny, który stopniowo tworzy złożony produkt przy użyciu odpowiednio złożonego protokołu. Prototyp ma obiekt fabryczny budujący produkt poprzez skopiowanie obiektu prototypowego. W tym przypadku obiekt fabryczny i prototyp są tym samym obiektem, ponieważ prototyp jest odpowiedzialny za zwrot produktu.

Maggyero
źródło