Jaka jest różnica między wzorem Design Builder a wzorem Factory Design?


662

Jaka jest różnica między wzorem projektowym Builder a wzorem fabrycznym?

Który jest bardziej korzystny i dlaczego?

Jak mogę przedstawić moje odkrycia jako wykres, jeśli chcę przetestować i porównać / porównać te wzorce?


12
Skoro robią różne rzeczy, co rozumiesz przez „korzystne”?
S.Lott

5
Konstruktor jest bardziej złożoną wersją konstruktora - podczas gdy metoda fabryczna jest uproszczona.
Dávid Horváth,

@ DávidHorváth Nie opisałbym Konstruktora jako „bardziej złożonego”. Kiedy masz do czynienia z konstruktorem, który ma 100 parametrów, a zależy ci tylko na 3 z nich i wiesz, że liczba parametrów może się zmienić w przyszłości, użycie wzorca konstruktora ułatwiłoby wszystkim życie.
Aberrant

@Aberrant Skomplikowane użytkowanie i złożoność architektoniczna to dwie różne rzeczy. Skupiłem się na tym drugim.
Dávid Horváth,

Odpowiedzi:


466

W przypadku wzorców projektowych zwykle nie ma „bardziej korzystnego” rozwiązania, które działałoby we wszystkich przypadkach. To zależy od tego, co musisz wdrożyć.

Z Wikipedii:

  • Konstruktor koncentruje się na konstruowaniu złożonego obiektu krok po kroku. Abstract Factory podkreśla rodzinę przedmiotów produktu (prostych lub złożonych). Konstruktor zwraca produkt jako ostatni krok, ale w przypadku Fabryki abstrakcyjnej produkt jest natychmiast zwracany.
  • Konstruktor często buduje kompozyt.
  • Często projekty zaczynają się od metody fabrycznej (mniej skomplikowane, bardziej konfigurowalne, podklasy rozprzestrzeniają się) i ewoluują w kierunku fabryki abstrakcyjnej, prototypu lub konstruktora (bardziej elastyczne, bardziej złożone), gdy projektant odkrywa, gdzie potrzebna jest większa elastyczność.
  • Czasami wzorce tworzenia są komplementarne: Konstruktor może użyć jednego z innych wzorów, aby zaimplementować, które komponenty zostaną zbudowane. Abstract Factory, Builder i Prototype mogą wykorzystywać Singleton w swoich implementacjach.

Wpis w Wikipedii dotyczący wzorca projektowania fabryki: http://en.wikipedia.org/wiki/Factory_method_pattern

Wpis w Wikipedii dotyczący wzorca projektowania konstruktora: http://en.wikipedia.org/wiki/Builder_pattern


159
To jest dokładnie różnica. Konstruktor jest potrzebny tylko wtedy, gdy nie można wytworzyć obiektu w jednym kroku. Doskonałym tego przykładem może być proces deserializacji dla złożonego obiektu. Często parametry obiektu złożonego muszą być pobierane jeden po drugim.
Bernard Igiri,

1
W pierwszym zdaniu powiedziałbym, że absolutnie często istnieje bardziej korzystne rozwiązanie, które ma szerokie zastosowanie ... po prostu ich nie widzimy, ponieważ ostatecznie zostają upieczone bezpośrednio w językach programowania.
Joel Coehoorn,

4
@Jel: Zgadzam się, że niektóre wzorce są bardziej powszechne niż inne (na przykład Fabryka wydaje się bardziej powszechna niż Builder), ale miałem na myśli to, że żaden z nich nie jest zawsze lepszy od drugiego, bez względu na to, jak wygląda scenariusz .
Adrian Grigore

@AdrianGrigore co jeśli zmieszać oba? ?? aso.net mvc mają ControllerBuilder, który ustawił i pobiera metodę dla klasy ControllerFactory
AminM

Dobra odpowiedź, chociaż 2 rzeczy, które warto dodać to: 1) Builder służy głównie do budowania POJO przy użyciu Fluent API (np. Person.builder (). WithName ("Sam"). WithAge (38) .build (). 2) W moim doświadczeniu konstruktor jest użyteczny do tworzenia POJO dla obiektów domeny, podczas gdy fabryka jest przydatna do tworzenia obiektów usług, takich jak klasa PdfGeneratorFactory. Obiekt serwisowy może być buforowany w fabryce w celu użycia go więcej niż 1 raz, podczas gdy konstruktor zawsze tworzy nowy obiekt zgodnie z projektem.
saurabh.in

358

Fabryka to po prostu funkcja otacza konstruktora (być może jedna z innej klasy). Kluczowa różnica polega na tym, że wzorzec metody fabrycznej wymaga zbudowania całego obiektu w jednym wywołaniu metody, a wszystkie parametry przekazane są w jednym wierszu. Ostateczny obiekt zostanie zwrócony.

Z drugiej strony wzorzec konstruktora jest w istocie obiektem opakowującym wszystkie możliwe parametry, które można przekazać do wywołania konstruktora. Pozwala to na użycie metod ustawiających do powolnego budowania listy parametrów. Jedną dodatkową metodą klasy budowniczej jest metoda build (), która po prostu przekazuje obiekt konstruktora do pożądanego konstruktora i zwraca wynik.

W językach statycznych, takich jak Java, staje się to ważniejsze, gdy masz więcej niż garść (potencjalnie opcjonalnych) parametrów, ponieważ pozwala to uniknąć konieczności posiadania konstruktorów teleskopowych dla wszystkich możliwych kombinacji parametrów. Konstruktor umożliwia także stosowanie metod ustawiających do definiowania pól tylko do odczytu lub pól prywatnych, których nie można bezpośrednio modyfikować po wywołaniu konstruktora.

Podstawowy przykład fabryki

// Factory
static class FruitFactory {
    static Fruit create(name, color, firmness) {
        // Additional logic
        return new Fruit(name, color, firmness);
    }
}

// Usage
Fruit fruit = FruitFactory.create("apple", "red", "crunchy");

Przykład podstawowego konstruktora

// Builder
class FruitBuilder {
    String name, color, firmness;
    FruitBuilder setName(name)         { this.name     = name;     return this; }
    FruitBuilder setColor(color)       { this.color    = color;    return this; }
    FruitBuilder setFirmness(firmness) { this.firmness = firmness; return this; }
    Fruit build() {
        return new Fruit(this); // Pass in the builder
    }
}

// Usage
Fruit fruit = new FruitBuilder()
        .setName("apple")
        .setColor("red")
        .setFirmness("crunchy")
        .build();

Warto porównać próbki kodu z tych dwóch stron Wikipedii:

http://en.wikipedia.org/wiki/Factory_method_pattern
http://en.wikipedia.org/wiki/Builder_pattern


1
To nie jest prawidłowe użycie wzorca budowniczego imo, nawet w linku wiki, który wstrzymałeś użycie jest inne. FruitBuilder to mieszanka składników Director i Builder, w której wywoływana jest build (), która powinna należeć do Director i ustawiaczy, które należą do komponentu Builder. Dyrektor powinien zawierać logikę biznesową dotyczącą sposobu tworzenia obiektów za pomocą metod konstruktorów. Płynne api nie są wzorcami konstruktora, a StringBuilder nie jest również wzorcem konstruktora.
Kmaczek

282

Wzorzec fabryczny można prawie postrzegać jako uproszczoną wersję wzorca budowniczego.

W fabryce wzór, fabryka jest odpowiedzialny za tworzenie różnych podtypów obiektu w zależności od potrzeb.

Użytkownik metody fabrycznej nie musi znać dokładnego podtypu tego obiektu. Przykład metody fabrycznej createCarmoże zwrócić obiekt Fordlub Hondaobiekt wpisany na maszynie.

We wzorze konstruktora różne podtypy są również tworzone za pomocą metody konstruktora, ale skład obiektów może się różnić w obrębie tej samej podklasy.

Aby kontynuować przykład samochodu, możesz mieć createCarmetodę konstruktora, która tworzy Hondaobiekt z motywem czterocylindrowym lub Hondaobiekt z motywem 6 cylindrów. Wzorzec konstruktora pozwala na tę drobną ziarnistość.

Diagramy zarówno wzoru konstruktora, jak i wzorca metody fabrycznej są dostępne na Wikipedii.


13
Wzorzec konstruktora przypomina powiększanie konstrukcji dużego obiektu. Duży obiekt składa się z innego obiektu, który składa się dalej na podobnej rekurencji. Podczas gdy fabryka dostarczy Ci to w jednym telefonie. Czy to zrozumienie jest prawidłowe?
Fooo

63

Wzorzec projektu konstruktora opisuje obiekt, który wie, jak wykonać inny obiekt określonego typu w kilku etapach. Utrzymuje stan potrzebny dla elementu docelowego na każdym etapie pośrednim. Zastanów się, przez co przechodzi StringBuilder, aby utworzyć końcowy ciąg.

Fabryczny wzorzec projektowy opisuje obiekt, który umie tworzyć kilka różnych, ale powiązanych rodzajów obiektów w jednym kroku, przy czym określony typ jest wybierany na podstawie podanych parametrów. Pomyśl o systemie serializacji, w którym tworzysz swój serializator, który tworzy pożądany obiekt w jednym wywołaniu obciążenia.


7
Tylko wskazówka: dobrym przykładem wzorca budowniczego jest „płynny interfejs”, a ADO.NET jest pełen implementacji „factory” i „abstract factory” (tj. DbFactory).
boj

50
  • Konstruowanie złożonego obiektu krok po kroku: wzorzec konstruktora

  • Prosty obiekt jest tworzony przy użyciu jednej metody: wzorca metody fabrycznej

  • Tworzenie obiektu za pomocą wielu metod fabrycznych: Abstrakcyjny wzór fabryczny


21

Wzorzec konstruktora i wzorzec fabryczny, oba wydają się bardzo podobne do gołych oczu, ponieważ oba tworzą obiekty dla Ciebie.

Ale musisz przyjrzeć się bliżej

Ten przykład z życia sprawi, że różnica między nimi będzie bardziej wyraźna.

Załóżmy, że poszedłeś do restauracji typu fast food i zamówiłeś jedzenie .

1) Jakie jedzenie?

Pizza

2) Jakie polewy?

Papryka, pomidor, kurczak z grilla, bez sosny

Tak więc różne rodzaje żywności są wytwarzane według wzoru Factory, ale różne warianty (smaki) określonego jedzenia są tworzone według wzoru Builder.

Różne rodzaje żywności

Pizza, Burger, Makaron

Warianty pizzy

Tylko ser, ser + pomidor + papryka, ser + pomidor itp.

Próbka kodu

Przykładową implementację kodu obu wzorców można zobaczyć tutaj
Wzorzec fabryczny wzorca budowniczego


1
Dziękujemy za podanie przykładowego kodu! Twoje przykłady bardzo dobrze różnicują te 2 wzorce.
Rommel Paras,

18

Oba są wzorami kreacyjnymi, aby stworzyć Obiekt.

1) Wzorzec fabryczny - Załóżmy, że masz jedną superklasę i N liczbę podklas. Obiekt tworzony zależy od tego, który parametr / wartość jest przekazywana.

2) Wzorzec konstruktora - aby utworzyć złożony obiekt.

Ex: Make a Loan Object. Loan could be house loan, car loan ,
    education loan ..etc. Each loan will have different interest rate, amount ,  
    duration ...etc. Finally a complex object created through step by step process.

12

Najpierw kilka ogólnych rzeczy, które należy podążać za moją argumentacją:

Głównym wyzwaniem przy projektowaniu dużych systemów oprogramowania jest to, że muszą być elastyczne i nieskomplikowane do zmiany. Z tego powodu istnieją pewne wskaźniki, takie jak sprzężenie i spójność. Aby uzyskać systemy, które można łatwo zmienić lub rozszerzyć funkcjonalnie, bez konieczności przeprojektowywania całego systemu od zera, możesz przestrzegać zasad projektowania (takich jak SOLID itp.). Po jakimś czasie jakiś programista uznał, że jeśli przestrzegają tych zasad, istnieje kilka podobnych rozwiązań, które działały dobrze w przypadku podobnych problemów. Te standardowe rozwiązania okazały się wzorami projektowymi.

Wzorce projektowe mają więc wspierać przestrzeganie ogólnych zasad projektowania w celu uzyskania luźno sprzężonych systemów o wysokiej spójności.

Odpowiedź na pytanie:

Pytając o różnicę między dwoma wzorami, musisz zadać sobie pytanie, jaki wzór sprawia, że ​​twój system jest bardziej elastyczny. Każdy wzorzec ma swój własny cel organizowania zależności między klasami w systemie.

Abstrakcyjny wzorzec fabryczny: GoF: „Zapewnij interfejs do tworzenia rodzin powiązanych lub zależnych obiektów bez określania ich konkretnych klas”.

Co to znaczy: Zapewniając taki interfejs, wywołanie konstruktora każdego z produktów rodziny jest zawarte w klasie fabrycznej. Ponieważ jest to jedyne miejsce w całym systemie, w którym nazywani są te konstruktory, możesz zmienić swój system, wdrażając nową klasę fabryczną. Jeśli wymienisz reprezentację fabryki za pośrednictwem innej, możesz wymienić cały zestaw produktów bez dotykania większości kodu.

Wzorzec konstruktora: GoF: „Oddziel konstrukcję złożonego obiektu od jego reprezentacji, aby ten sam proces budowy mógł tworzyć różne reprezentacje”.

Co to znaczy: obudowujesz proces budowy w innej klasie, zwanej reżyserem (GoF). Ten dyrektor zawiera algorytm tworzenia nowych instancji produktu (np. Komponuje złożony produkt z innych części). Do stworzenia integralnych części całego produktu reżyser używa konstruktora. Wymieniając konstruktor w reżyserze, możesz użyć tego samego algorytmu do stworzenia produktu, ale zmienić reprezentacje pojedynczych części (a więc i reprezentację produktu). Aby rozszerzyć lub zmodyfikować system w reprezentacji produktu, wystarczy zaimplementować nową klasę konstruktora.

W skrócie: Celem Abstrakcyjnego Wzorca Fabryki jest wymiana zestawu produktów, które są przeznaczone do wspólnego użytku. Wzorzec konstruktora ma na celu obudowanie abstrakcyjnego algorytmu tworzenia produktu w celu ponownego wykorzystania go do różnych reprezentacji produktu.

Moim zdaniem nie można powiedzieć, że Abstrakcyjny Wzór Fabryki jest starszym bratem Wzorca Budowniczego. TAK, oba są wzorami kreacyjnymi, ale ich główna intencja jest zupełnie inna.


ładna odpowiedź, wyszukane wyjaśnienie.
holuj

czy możesz wyjaśnić znaczenie „Oddziel budowę złożonego obiektu od jego reprezentacji”
Rajdeep,

@Rajdeep wyjaśnieniem jest tęsknota za komentarzem, dlatego napisałem inną odpowiedź.
Janis

@Janis Gdzie jest ta odpowiedź lub źródło, z którego mogę czytać?
Rajdeep,

@Rajdeep Polecam przeczytać książkę „Wzory projektowe” - amazon.de/Patterns-Elements-Reusable-Object-Oriented-Software/…
Janis

7

Jedną uderzającą różnicą między Builderem a fabryką, którą mogłem zauważyć, była następująca

załóżmy, że mamy samochód

class Car
{
  bool HasGPS;
  bool IsCityCar;
  bool IsSportsCar;
  int   Cylenders;
  int Seats;

  public:
     void Car(bool hasGPs=false,bool IsCityCar=false,bool IsSportsCar=false, int Cylender=2, int Seats=4);
 };

W powyższym interfejsie możemy uzyskać samochód w następujący sposób:

 int main()
 {
    BadCar = new Car(false,false,true,4,4);
  }

ale co jeśli zdarzy się jakiś wyjątek podczas tworzenia miejsc ??? W OGÓLE NIE MASZ OBIEKTU // ALE

załóżmy, że masz implementację taką jak poniżej

class Car
 {
    bool mHasGPS;
    bool mIsCityCar;
    bool mIsSportsCar;
    int mCylenders;
    int mSeats;

 public:
    void Car() : mHasGPs(false), mIsCityCar(false), mIsSportsCar(false), mCylender(2), mSeats(4) {}
    void SetGPS(bool hasGPs=false)  {mHasGPs = hasGPs;}
    void SetCity(bool CityCar)  {mIsCityCar = CityCar;}
    void SetSports(bool SportsCar)  {mIsSportsCar = SportsCar;}
    void SetCylender(int Cylender)  {mCylenders = Cylender;}    
    void SetSeats(int seat) {mSeats = seat;}    
};

 class CarBuilder 
 {
    Car* mCar;
public:
        CarBuilder():mCar(NULL) {   mCar* = new Car();  }
        ~CarBuilder()   {   if(mCar)    {   delete mCar;    }
        Car* GetCar()   {   return mCar; mCar=new Car();    }
        CarBuilder* SetSeats(int n) {   mCar->SetSeats(n); return this; }
        CarBuilder* SetCylender(int n)  {   mCar->SetCylender(n); return this;  }
        CarBuilder* SetSports(bool val) {   mCar->SetSports(val); return this;  }
        CarBuilder* SetCity(bool val)   {   mCar->SetCity(val); return this;    }
        CarBuilder* SetGPS(bool val)    {   mCar->SetGPS(val); return this; }
}

Teraz możesz tworzyć w ten sposób

 int main()
 {
   CarBuilder* bp =new CarBuilder;
    Car* NewCar  = bp->SetSeats(4)->SetSports(4)->SetCity(ture)->SetGPS(false)->SetSports(true)->GetCar();

     bp->SetSeats(2);

     bp->SetSports(4);

     bp->SetCity(ture);

     bp->SetSports(true)

     Car* Car_II=  bp->GetCar();

  }

Tutaj, w drugim przypadku, nawet jeśli jedna operacja się nie powiedzie, nadal dostaniesz samochód.

Być może później samochód nie będzie działał idealnie, ale będziesz miał obiekt.

Ponieważ metoda fabryczna daje samochód w jednym wywołaniu, podczas gdy Konstruktor buduje jeden po drugim.

Chociaż zależy to od potrzeb rycerza, który wybrać.


2
Z pewnością lepiej nie mieć żadnego samochodu niż samochód nieważny - co, jeśli znajdziesz problem tylko wtedy, gdy skorzystasz z przerw?
Ken,

@Ken: Nie twierdzę, że jest to dobry projekt z perspektywy komercyjnego projektu itp., Raczej zamiar przytoczenia tego przykładu w celu zilustrowania różnicy między wzorami. Zdecydowanie masz rację, że jest to złe z doświadczenia użytkownika, że ​​otrzymywanie złego samochodu, ale rozważmy, że jest fabryka, w której produkowane są samochody i pewna część źle funkcjonuje, a następnie samochód jest produkowany, ale ze złą przerwą, którą można znaleźć w czas testowania i wysyłki tego samochodu do klienta jest zatrzymany.
Fooo

2
Chciałbym wyjaśnić, że tak naprawdę jestem wielkim fanem wzorca budowniczego, jednak nie z tego powodu, który podałeś. Obiekt, który jest nieprawidłowy, powinien zawieść przy budowie, im dalej w trakcie procesu znaleziono błąd, tym jest on droższy. W przypadku wzorca konstruktora normalne byłoby, aby metoda kompilacji (w twoim przykładzie o nazwie getCar ()) zgłaszała wyjątek, jeśli brakuje wymaganych danych.
Ken

7
+-------------------------------------------------------------------+---------------------------------------------------+
|                              Builder                              |                      Factory                      |
+-------------------------------------------------------------------+---------------------------------------------------+
| Return only single instance to handle complex object construction | Retrun various instances on multiple constructors |
| No interface required                                             | Interface driven                                  |
| Inner classes is involved (to avoid telescopic constructors)      | Subclasses are involved                           |
+-------------------------------------------------------------------+---------------------------------------------------+  

Konstruktor teleskopowy

Analogia:

  • Fabryka: rozważ restaurację. Stworzenie „dzisiejszego posiłku” jest wzorcem fabrycznym, ponieważ mówisz kuchni „przynieś mi dzisiejszy posiłek”, a kuchnia (fabryka) decyduje o tym, który obiekt wygenerować, na podstawie ukrytych kryteriów.
  • Builder: Builder pojawia się, jeśli zamówisz niestandardową pizzę. W tym przypadku kelner mówi szefowi kuchni (budowniczy) „Potrzebuję pizzy; dodaj do niej ser, cebulę i bekon!” W ten sposób konstruktor ujawnia atrybuty, które powinien mieć wygenerowany obiekt, ale ukrywa, jak je ustawić.

Kurtuazja


5

Builder i Abstract Factory mają różne przeznaczenie. W zależności od właściwego zastosowania należy wybrać odpowiedni wzór.

Istotne cechy Buildera :

  1. Wzorzec konstruktora buduje złożony obiekt przy użyciu prostych obiektów i podejścia krok po kroku
  2. Klasa Builder buduje ostateczny obiekt krok po kroku. Ten konstruktor jest niezależny od innych obiektów
  3. Wymiana na metodę Factory / Abstract Factory w tym scenariuszu: zbyt wiele argumentów do przekazania z programu klienta do klasy Factory, które mogą być podatne na błędy
  4. Niektóre parametry mogą być opcjonalne, w przeciwieństwie do fabryki, która wymusza przesłanie wszystkich parametrów

Istotne cechy fabryczne (prosta fabryka):

  1. Wzór kreacyjny
  2. Na podstawie dziedziczenia
  3. Fabryka zwraca metodę fabryczną (interfejs), która z kolei zwraca konkretny obiekt
  4. Możesz zastąpić nowe konkretne obiekty interfejsem, a klient (osoba dzwoniąca) nie powinna być świadoma wszystkich konkretnych implementacji
  5. Klient zawsze ma dostęp tylko do interfejsu i można ukryć szczegóły tworzenia obiektu w metodzie Factory.

Często projekty zaczynają się od metody fabrycznej (mniej skomplikowane, bardziej konfigurowalne, podklasy rozprzestrzeniają się) i ewoluują w kierunku fabryki abstrakcyjnej , prototypu lub konstruktora (bardziej elastyczne, bardziej złożone)

Zobacz powiązane posty:

Utrzymywanie konstruktora w osobnej klasie (płynny interfejs)

Wzory projektowe: Fabryka kontra metoda fabryczna kontra fabryka abstrakcyjna

Więcej informacji można znaleźć w poniższych artykułach:

zaopatrzenie

dziennikaldev


5

Fabryka : Służy do tworzenia instancji obiektu, w której zależności obiektu są całkowicie utrzymywane przez fabrykę. W przypadku abstrakcyjnego wzorca fabryki często istnieje wiele konkretnych implementacji tej samej abstrakcyjnej fabryki. Właściwa implementacja fabryki jest wprowadzana poprzez wstrzykiwanie zależności.

Konstruktor : służy do budowania niezmiennych obiektów, gdy zależności obiektu, który ma zostać utworzony, są częściowo znane z góry, a częściowo dostarczane przez klienta konstruktora.


4

Wzory abstrakcyjne Fabryki i Konstruktora są wzorami Kreacyjnymi, ale mają różne intencje.

Abstrakcyjny wzór fabryczny podkreśla tworzenie obiektów dla rodzin powiązanych obiektów, w których:

  • Każda rodzina jest zbiorem klas pochodzących ze wspólnej klasy podstawowej / interfejsu.
  • Każdy obiekt jest zwracany natychmiast w wyniku jednego wywołania.

Wzorzec konstruktora koncentruje się na konstruowaniu złożonego obiektu krok po kroku. Oddziela reprezentację od procesu konstruowania złożonego obiektu, dzięki czemu ten sam proces budowy można zastosować do różnych reprezentacji.

  • Obiekt konstruktora hermetyzuje konfigurację złożonego obiektu.
  • Obiekt Director zna protokół korzystania z Konstruktora, w którym protokół określa wszystkie logiczne kroki wymagane do zbudowania złożonego obiektu.

czy możesz wyjaśnić znaczenie „oddzielenia reprezentacji od procesu konstruowania złożonego obiektu”
Rajdeep,

3

Złożona konstrukcja ma miejsce, gdy obiekt, który ma zostać zbudowany, składa się z różnych innych obiektów reprezentowanych przez abstrakcje.

Rozważ menu w McDonald's. Menu zawiera napój, danie główne i boczne. W zależności od tego, którzy potomkowie poszczególnych abstrakcji są skomponowani razem, utworzone menu ma inną reprezentację.

  1. Przykład: Cola, Big Mac, frytki
  2. Przykład: Sprite, samorodki, curly frytki

Tam mamy dwa wystąpienia menu z różnymi reprezentacjami. Z kolei proces budowy pozostaje taki sam. Tworzysz menu z drinkiem, daniem głównym i bocznym.

Używając wzorca konstruktora, oddzielasz algorytm tworzenia złożonego obiektu od różnych komponentów użytych do jego utworzenia.

Pod względem wzorca konstruktora algorytm jest zamknięty w dyrektorze, natomiast konstruktory służą do tworzenia integralnych części. Różnicowanie używanego konstruktora w algorytmie reżysera powoduje inną reprezentację, ponieważ inne części składają się w menu. Sposób tworzenia menu pozostaje taki sam.


1
To wyjaśnia „oddzielenie budowy złożonego obiektu od jego reprezentacji”
Rajdeep

2

Główna różnica między nimi polega na tym, że wzorzec Konstruktora opisuje przede wszystkim tworzenie złożonych obiektów krok po kroku. We wzorze fabryki abstrakcyjnej nacisk kładziony jest na rodziny przedmiotów-produktów . Konstruktor zwraca produkt w ostatnim kroku . Podczas gdy we wzorze Abstract Factory produkt jest dostępny natychmiast .

Przykład: Powiedzmy, że tworzymy Labirynt

1. Fabryka abstrakcyjna:

Maze* MazeGame::CreateMaze (MazeFactory& factory) {
Maze* maze = factory.MakeMaze(); /// product is available at start!!
 /* Call some methods on maze */
return maze;
}

2. Konstruktor:

Maze* MazeGame::CreateMaze (MazeBuilder& builder) {
builder.buildMaze(); /// We don't have access to maze
 /* Call some methods on builder */
return builder.GetMaze();
}

2

Uważam, że użycie i różnica między wzorcami Factory i Builder można łatwiej zrozumieć / wyjaśnić w pewnym okresie czasu, gdy pracujesz na tej samej podstawie kodu i zmieniających się wymaganiach.

Z mojego doświadczenia wynika, że ​​zwykle zaczynasz od wzorca fabrycznego zawierającego kilka statycznych metod twórczych, aby przede wszystkim ukryć stosunkowo złożoną logikę inicjalizacji. W miarę jak twoja hierarchia obiektów staje się bardziej złożona (lub gdy dodajesz więcej typów, parametrów), prawdopodobnie twoje metody są zapełniane większą liczbą parametrów i nie wspominając o tym, że będziesz musiał ponownie skompilować moduł Factory. Wszystkie te rzeczy zwiększają złożoność metod twórców, zmniejszają czytelność i sprawiają, że moduł tworzenia jest bardziej kruchy.

Ten punkt prawdopodobnie będzie punktem przejścia / rozszerzenia. W ten sposób utworzysz moduł otoki wokół parametrów konstrukcyjnych, a następnie będziesz mógł reprezentować nowe (podobne) obiekty, dodając więcej abstrakcji (być może) i implementacji bez dotykania faktycznej logiki tworzenia. Masz więc „mniej” złożoną logikę.

Szczerze mówiąc, różnica w czymś w rodzaju „posiadania obiektu utworzonego w jednym lub wielu krokach jest różnicą”, ponieważ jedyny czynnik różnorodności nie był dla mnie wystarczający, aby je rozróżnić, ponieważ mogłem używać obu sposobów w prawie wszystkich przypadkach, z którymi miałem do czynienia teraz bez żadnych korzyści. Więc to w końcu o tym pomyślałem.


2

Główną zaletą wzorca konstruktora w porównaniu do wzorca fabrycznego jest to, że jeśli chcesz stworzyć jakiś standardowy obiekt z wieloma możliwymi dostosowaniami, ale zwykle kończy się to dostosowywaniem tylko kilku.

Na przykład, jeśli chcesz napisać klienta HTTP - skonfigurujesz pewne domyślne parametry, takie jak domyślny limit czasu zapisu / odczytu, protokoły, pamięć podręczna, DNS, przechwytywacze itp.

Większość użytkowników Twojego klienta będzie po prostu używać tych domyślnych parametrów, podczas gdy niektórzy inni użytkownicy mogą chcieć dostosować niektóre z pozostałych parametrów. W niektórych przypadkach wystarczy zmienić limity czasu i wykorzystać resztę bez zmian, aw innych przypadkach może być konieczne dostosowanie na przykład pamięci podręcznej.

Oto możliwe sposoby tworzenia instancji klienta (wzięte z OkHttpClient):

//just give me the default stuff
HttpClient.Builder().build()   

//I want to use custom cache
HttpClient.Builder().cache(MyCache()).build() 

//I want custom connection timeout
HttpClient.Builder().connectTimeout(30, TimeUnit.SECONDS).build() 

//I am more interested in read/write timeout
HttpClient.Builder()
        .readTimeout(30, TimeUnit.SECONDS)
        .writeTimeout(30, TimeUnit.SECONDS).build()

Jeśli użyjesz do tego wzoru fabrycznego, skończysz pisać wiele metod ze wszystkimi możliwymi kombinacjami parametrów tworzenia. Dzięki konstruktorowi określasz tylko te, na których Ci zależy, i pozwalasz konstruktorowi zbudować go, aby zajął się wszystkimi innymi parametrami.


1

Wzorzec budowy kładzie nacisk na złożoność tworzenia obiektu (rozwiązany przez „kroki”)

Abstrakcyjny wzór kładzie nacisk na „tylko” na „abstrakcję” (wielu, ale powiązanych) obiektów.


1

Różnica jest wyraźna We wzorcu konstruktora konstruktor utworzy dla Ciebie określony typ obiektu. Musisz powiedzieć, co budowniczy ma zbudować. We wzorcu fabrycznym, używając klasy abstrakcyjnej, bezpośrednio budujesz konkretny obiekt.

Tutaj klasa konstruktora działa jako mediator między klasą główną a klasami określonego typu. Więcej abstrakcji.


1

Oba są bardzo podobne, ale jeśli masz dużą liczbę parametrów do tworzenia obiektów, a niektóre z nich są opcjonalne z pewnymi wartościami domyślnymi, wybierz wzorzec Konstruktora.


1

moim zdaniem

Konstruktor jest bardziej złożoną fabryką.

Ale w programie Builder można tworzyć instancje obiektów za pomocą innych fabryk , które są wymagane do zbudowania ostatecznego i poprawnego obiektu.

Mówiąc o ewolucji „Wzorów Kreacyjnych” według złożoności, możesz o tym pomyśleć w ten sposób:

Dependency Injection Container -> Service Locator -> Builder -> Factory

1

Oba wzorce mają tę samą potrzebę: ukryj przed kodem klienta logikę budowy złożonego obiektu. Ale co sprawia, że ​​„złożony” (a czasem komplikuje) obiekt? Głównie wynika to z zależności, a raczej ze stanu obiektu złożonego z bardziej częściowych stanów. Konstruktor może wstrzykiwać zależności, aby ustawić początkowy stan obiektu, ale obiekt może wymagać ich wielu, niektóre będą w domyślnym stanie początkowym (tylko dlatego, że powinniśmy się dowiedzieć, że ustawienie domyślnej zależności na wartość null nie jest najczystszym sposobem ) i niektóre inne ustawione na stan sterowany przez jakiś warunek. Ponadto istnieją właściwości obiektów, które są pewnego rodzaju „nieświadomymi zależnościami”, ale mogą również przyjmować stany opcjonalne.

istnieją dwa dobrze znane sposoby zdominowania tej złożoności:

  • Kompozycja / agregacja: Zbuduj obiekt, zbuduj zależne obiekty, a następnie połącz ze sobą. Tutaj konstruktor może uczynić proces przejrzystym i elastycznym, który określa reguły, które prowadzą do budowy komponentu.

  • Polimorfizm: reguły budowy są deklarowane bezpośrednio w definicji podtypu, więc masz zestaw reguł dla każdego podtypu, a niektóre warunki decydują, który z tych zestawów reguł ma zastosowanie do budowy obiektu. Fabryka idealnie pasuje do tego scenariusza.

Nic nie stoi na przeszkodzie, aby połączyć te dwa podejścia. Rodzina produktów może tworzyć abstrakcyjne obiekty za pomocą konstruktora, konstruktor może wykorzystywać fabryki do określania, który obiekt komponentu tworzy się.


0

Moim zdaniem wzorzec Konstruktora jest używany, gdy chcesz utworzyć obiekt z szeregu innych obiektów, a tworzenie części musi być niezależne od obiektu, który chcesz utworzyć. Pomaga ukryć tworzenie części przed klientem, aby konstruktor i klient byli niezależni. Służy do tworzenia złożonych obiektów (obiektów, które mogą składać się ze skomplikowanych właściwości)

Podczas gdy wzorzec fabryczny określa, że ​​chcesz tworzyć obiekty ze wspólnej rodziny i chcesz, aby była od razu cerowana. Służy do prostszych obiektów.


0

Konstruktor i fabryka abstrakcyjna

Wzorzec projektowy Konstruktora jest w pewnym stopniu bardzo podobny do wzorca Fabryki abstrakcyjnej. Dlatego ważne jest, aby móc rozróżniać sytuacje, w których jedno lub drugie jest używane. W przypadku Fabryki Abstrakcji klient wykorzystuje metody fabryki do tworzenia własnych obiektów. W przypadku Konstruktora klasa Builder jest instruowana, jak utworzyć obiekt, a następnie jest o to proszona, ale sposób, w jaki klasa jest złożona, zależy od klasy Builder, przy czym ten szczegół różnicuje oba wzorce.

Wspólny interfejs dla produktów

W praktyce produkty tworzone przez budowniczych betonu mają znacznie inną strukturę, więc jeśli nie ma powodu, aby czerpać różne produkty, wspólna klasa nadrzędna. To także odróżnia wzorzec Konstruktora od wzorca Fabryki abstrakcyjnej, który tworzy obiekty pochodzące z typowego typu.

Od: http://www.oodesign.com/builder-pattern.html


-2

Wzorzec fabryczny tworzy konkretną implementację klasy w czasie wykonywania, tj. Jej głównym celem jest użycie polimorfizmu, aby umożliwić podklasom decydowanie, która klasa ma zostać utworzona. Oznacza to, że w czasie kompilacji nie znamy dokładnej klasy, która zostanie utworzona, podczas gdy wzorzec Konstruktora zajmuje się głównie rozwiązywaniem problemu teleskopowego konstruowania antipatternu, który powstaje z powodu dużej liczby opcjonalnych pól klasy. We wzorcu konstruktora nie ma pojęcia polimorfizmu, ponieważ wiemy, jaki obiekt próbujemy zbudować w czasie kompilacji.

Jedynym wspólnym tematem tych dwóch wzorów jest ukrywanie konstruktorów i tworzenie obiektów za metodami fabrycznymi oraz metoda budowania w celu poprawy konstrukcji obiektów.


-2

Wzorzec fabryczny pozwala od razu utworzyć obiekt, a wzorzec konstruktora pozwala przerwać proces tworzenia obiektu. W ten sposób możesz dodać inną funkcjonalność podczas tworzenia obiektu.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.