Konstruktorzy a metody fabryczne

Podczas modelowania klas, jaki jest preferowany sposób inicjalizacji:

  1. konstruktory lub
  2. Metody Fabryczne

A jakie byłyby względy wykorzystania któregokolwiek z nich?

W pewnych sytuacjach wolę mieć metodę fabryczną, która zwraca null, jeśli obiekt nie może być skonstruowany. To sprawia, że kod jest schludny. Mogę po prostu sprawdzić, czy zwracana wartość nie jest null przed podjęciem alternatywnej akcji, w przeciwieństwie do rzucania wyjątku z konstruktor. (Osobiście nie lubię WYJĄTKÓW)

Powiedzmy, że mam konstruktor na klasie, która oczekuje wartości id. Konstruktor używa tej wartości do wypełnienia klasy z bazy danych. W przypadku, gdy rekord o podanym id nie istnieje, konstruktor wyrzuca Rekordnotfoundexception. W tym przypadku będę musiał dołączyć budowę wszystkich takich klas w ramach próby../ align = "left" /

W przeciwieństwie do tego mogę mieć statyczną metodę fabryczną na tych klasach która zwróci null, jeśli rekord nie zostanie znaleziony.

Które podejście jest lepsze w tym przypadku, konstruktor czy metoda fabryczna?

 144
Author: Hannele, 2009-03-10

10 answers

[[0]}ze strony 108 z wzorce projektowe: elementy oprogramowania Obiektowego wielokrotnego użytku przez Gamma, Helm, Johnson i Vlissides.

Użyj wzorca metody Fabrycznej, gdy

  • klasa nie może przewidzieć klasy obiektów, które musi utworzyć
  • Klasa chce, aby jej podklasy określały obiekty, które tworzy
  • klasy delegują odpowiedzialność do jednej z kilku podklas pomocniczych, a Ty chcesz zlokalizować wiedzę, która podklasa pomocnicza jest delegat
 60
Author: Glenn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-27 12:36:03

Zadaj sobie pytanie, czym one są i dlaczego je mamy. Oba służą do tworzenia instancji obiektu.

ElementarySchool school = new ElementarySchool();
ElementarySchool school = SchoolFactory.Construct(); // new ElementarySchool() inside
Jak na razie nie ma różnicy. Teraz wyobraźmy sobie, że mamy różne typy szkół i chcemy przełączyć się z korzystania z ElementarySchool na HighSchool (który pochodzi z ElementarySchool lub implementuje ten sam interfejs co ElementarySchool). Zmiana kodu to:
HighSchool school = new HighSchool();
HighSchool school = SchoolFactory.Construct(); // new HighSchool() inside

W przypadku interfejsu mielibyśmy:

ISchool school = new HighSchool();
ISchool school = SchoolFactory.Construct(); // new HighSchool() inside

Teraz jeśli masz ten kod w wielu miejscach widać, że używanie metody fabrycznej może być dość tanie, ponieważ po zmianie metody fabrycznej jest gotowe (jeśli użyjemy drugiego przykładu z interfejsami).

I to jest główna różnica i zaleta. Kiedy zaczynasz zajmować się złożoną hierarchią klas i chcesz dynamicznie tworzyć instancję klasy z takiej hierarchii, otrzymujesz następujący kod. Metody fabryczne mogą wtedy pobierać parametr, który mówi metodzie, jaką konkretną instancję instantiate. Załóżmy, że masz klasę Mistudent i musisz utworzyć odpowiedni obiekt ISchool, aby twój uczeń był członkiem tej szkoły.

ISchool school = SchoolFactory.ConstructForStudent(myStudent);

Teraz masz jedno miejsce w aplikacji, które zawiera logikę biznesową, która określa, jaki obiekt ISchool utworzyć instancję dla różnych obiektów IStudent.

So-dla klas prostych (obiekty wartości, itp.) constructor jest po prostu w porządku (nie chcesz przeinżynierować aplikacji), ale dla złożonych hierarchii klas fabrycznych metoda jest preferowanym sposobem.

W ten sposób postępujesz zgodnie z pierwszą zasadą projektowania z gang of four book "Program do interfejsu, a nie implementacji".

 162
Author: David Pokluda,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-10 05:27:05

Musisz przeczytać (jeśli masz dostęp do) efektywna Java 2 Pozycja 1: rozważ statyczne metody fabryczne zamiast konstruktorów.

Statyczne metody fabryczne zalety:

    Mają imiona.
  1. nie są wymagane do tworzenia nowego obiektu za każdym razem, gdy są wywoływane.
  2. mogą zwrócić obiekt dowolnego podtypu swojego typu return.
  3. zmniejszają dokładność tworzenia sparametryzowanych instancji typu.

Static factory wady metod:

  1. Gdy dostarczamy tylko statyczne metody fabryczne, klasy bez publicznych lub chronionych konstruktorów nie mogą być podklasowane.
  2. nie są łatwo odróżnialne od innych metod statycznych
 58
Author: cherouvim,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-10 07:26:10

Domyślnie, konstruktory powinny być preferowane, ponieważ są prostsze do zrozumienia i zapisu. Jeśli jednak trzeba oddzielić konstrukcję obiektu od jego znaczenia semantycznego rozumianego przez kod klienta, lepiej byłoby użyć fabryk.

Różnica między konstruktorami a fabrykami jest analogiczna do np. zmiennej i wskaźnika do zmiennej. Jest inny poziom indrection, co jest wadą; ale jest inny poziom elastyczności, co jest zaletą. Tak więc podczas dokonywania wyboru, byłoby dobrze radzi, aby zrobić tę analizę kosztów w stosunku do korzyści.

 23
Author: Frederick The Fool,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-10 04:41:21

Cytat z "efektywnej Javy", wyd.II, Poz. 1: rozważ statyczne metody fabryczne zamiast konstruktorów, str. 5:

"zauważ, że statyczna metoda fabryczna nie jest taka sama jak wzór metody Fabrycznej z wzorców projektowych [Gamma95, s. 107]. Statyczna metoda fabryczna opisana w pozycja ta nie ma bezpośredniego odpowiednika we wzorach projektowych."

 11
Author: Eugen Labun,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-27 22:50:50

Używaj fabryki tylko wtedy, gdy potrzebujesz dodatkowej kontroli przy tworzeniu obiektów, w sposób, którego nie można zrobić z konstruktorami.

Fabryki mają możliwość buforowania np.

Innym sposobem użycia fabryk jest scenariusz, w którym nie wiesz, jaki typ chcesz skonstruować. Często widzisz ten typ użycia w scenariuszach fabrycznych wtyczek, gdzie każda wtyczka musi pochodzić z baseclass lub zaimplementować jakiś interfejs. Fabryka tworzy instancje klas, które wywodzą się z baseclass lub implementują interfejs.

 11
Author: Patrick Peters,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-27 17:08:44

Konkretny przykład z aplikacji CAD / CAM.

Ścieżka cięcia byłaby wykonana przy użyciu konstruktora. Jest to szereg linii i łuków definiujących ścieżkę do przecięcia. O ile szereg linii i łuków może być różny i mieć różne współrzędne, to łatwo je obsługiwać, przekazując listę do konstruktora.

Kształt byłby wykonany za pomocą fabryki. Ponieważ chociaż istnieje klasa kształtu, każdy kształt byłby ustawiony inaczej w zależności od tego, jaki to jest rodzaj kształtu. My nie wiedzieć, jaki kształt będziemy inicjować, dopóki użytkownik nie dokona wyboru.

 7
Author: RS Conley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-10 12:30:42

Powiedzmy, że mam konstruktor na klasie, która oczekuje wartości id. Konstruktor używa tej wartości do wypełnienia klasy z bazy danych.

Ten proces powinien zdecydowanie znajdować się poza konstruktorem.

  1. Konstruktor nie powinien uzyskiwać dostępu do bazy danych.

  2. Zadaniem konstruktora jest zainicjalizowanie elementów danych i ustanowienie niezmiennika klasy za pomocą wartości przekazywanych do konstruktor.

  3. Dla wszystkiego innego lepszym podejściem jest użycie statycznej metody fabrycznej lub w bardziej złożonych przypadkach oddzielnej klasy factory lub builder .

Niektóre linie przewodnie konstruktora z Microsoft :

Wykonaj minimalną pracę w konstruktorze. Konstruktorzy nie powinni wykonywać wiele pracy poza przechwytywaniem parametrów konstruktora. Koszt innego przetwarzania powinien być opóźniony do wymagane.

I

Rozważ użycie statycznej metody fabrycznej zamiast konstruktora, jeśli semantyka żądanej operacji nie mapuje bezpośrednio do budowy nowej instancji.

 3
Author: Lightman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-22 10:17:06

Oprócz" efektywnej Javy "(jak wspomniano w innej odpowiedzi)," czysty kod " stwierdza również, że: preferuje statyczne metody fabryczne (z nazwami opisującymi argumenty) zamiast przeciążonych konstruktorów. Np. nie pisz

Complex complex = new Complex(23.0);

Ale zamiast tego napisz

Complex complex = Complex.fromRealNumber(23.0);

Książka sięga tak daleko, że sugeruje, aby konstruktor Complex(float) był PRYWATNY, aby zmusić użytkownika do wywołania statycznej metody fabrycznej.

 1
Author: blue_note,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-04 14:47:04

Czasami trzeba sprawdzić/obliczyć pewne wartości/warunki podczas tworzenia obiektu. A jeśli może rzucić wyjątek-constructro jest bardzo zły sposób. Więc musisz zrobić coś takiego:

var value = new Instance(1, 2).init()
public function init() {
    try {
        doSome()
    }
    catch (e) {
        soAnotherSome()
    }
}

Gdzie wszystkie dodatkowe obliczenia są w INIT (). Ale tylko Ty jako deweloper realy wiesz o tym init (). I oczywiście po miesiącach po prostu o tym zapominasz. Ale jeśli masz fabrykę-po prostu zrób wszystko, czego potrzebujesz w jednej metodzie z ukryciem tego init () przed wywołaniem bezpośrednim - więc nie ma problemów. Dzięki takiemu podejściu nie ma problemów z spadkiem na tworzenie i wyciek pamięci.

Ktoś ci powiedział o buforowaniu. Dobre. Ale musisz również pamiętać o wzorze masy ciała, który jest miły w użyciu z fabrycznym sposobem.
 0
Author: R1K0,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-29 14:34:24