2009-03-10 15 views
132

Podczas modelowania klas, co jest preferowanym sposobem inicjowania:Konstruktorzy vs Metod fabrycznych

  1. Konstruktorzy lub
  2. Fabryka Formy

i jakie byłyby rozważania dotyczące korzystania z któregokolwiek z nich ?

W niektórych sytuacjach wolę mieć metodę fabryczną, która zwraca wartość null, jeśli obiekt nie może zostać skonstruowany. To sprawia, że ​​kod jest zgrabny. Mogę po prostu sprawdzić, czy zwrócona wartość nie jest pusta przed podjęciem alternatywnej akcji, w przeciwieństwie do wypisania wyjątku od konstruktora. (Osobiście nie lubię wyjątków)

Powiedzmy, mam konstruktora na klasie, która oczekuje wartości id. Konstruktor używa tej wartości do zapełnienia klasy z bazy danych. W przypadku, gdy rekord z podanym identyfikatorem nie istnieje, konstruktor generuje wyjątek RecordNotFoundException. W takim przypadku będę musiał zamknąć konstrukcję wszystkich takich klas w bloku try..catch.

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

Które podejście jest lepsze w tym przypadku, metodą konstruktora lub fabryki?

Odpowiedz

60

Od strony 108 Design Patterns: Elements of Reusable Object-Oriented Software by Gamma, Helm, Johnson, and Vlissides.

użyć wzorca Factory Method gdy

  • klasa nie może przewidzieć klasę obiektów musi tworzyć
  • klasa chce jej podklasy określić obiekty tworzy klasy
  • delegować odpowiedzialność do jednej z kilku podklas pomocników, a chcesz zlokalizować wiedzę o tym, która podklasa pomocnika jest delegatem
+17

Statyczna metoda fabryczna różni się od wzoru projektu GoF - Factory Method Pattern. http://stackoverflow.com/questions/929021/what-are-static-factory-methods-in-java –

+0

Proszę nie porównywać z wzorcem metody Factory wzorców projektowych GoF. –

+80

to mi nic nie wyjaśnia – Sushant

23

Domyślnie należy preferować konstruktorów, ponieważ są one prostsze do zrozumienia i napisania. Jeśli jednak musisz oddzielić konstruktywne elementy obiektu od jego znaczenia semantycznego w rozumieniu kodu klienta, lepiej będzie, jeśli użyjesz fabryk.

Różnica między konstruktorami a fabrykami jest analogiczna do, powiedzmy, zmiennej i wskaźnika do zmiennej. Jest inny poziom pośrednictwa, co jest wadą; ale jest też inny poziom elastyczności, co jest zaletą. Dokonując wyboru, dobrze byłoby zrobić to w porównaniu do analizy korzyści.

+13

Tak więc (styl TDD) można rozpocząć od konstruktorów jako najprostszy sposób wykonania zadania. A następnie refaktoryzacji fabryk, gdy zacznie się zapach kodu (jak powtarzająca się logika warunkowa określająca, który konstruktor wywołuje)? – AndyM

+0

Absolutnie @ AndyM –

145

Zadaj sobie pytanie, czym one są i dlaczego je mamy. Obaj są po to, aby stworzyć instancję obiektu.

ElementarySchool school = new ElementarySchool(); 
ElementarySchool school = SchoolFactory.Construct(); // new ElementarySchool() inside 

Nie ma różnicy do tej pory. Teraz wyobraź sobie, że mamy różne typy szkół i chcemy przełączyć się z ElementarySchool na HighSchool (który wywodzi się z ElementarySchool lub implementuje ten sam interfejs ISchool jako ElementarySchool).Zmiana kodu będzie:

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

W przypadku interfejsu musielibyśmy:

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

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

I to jest główna różnica i zaleta. Kiedy zaczynasz radzić sobie ze złożonymi hierarchiami klas i chcesz dynamicznie tworzyć instancję klasy z takiej hierarchii, otrzymasz następujący kod. Fabryczne metody mogą następnie przyjmować parametr, który określa metodę konkretnej instancji do utworzenia instancji. Załóżmy, że masz klasę MyStudent 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 swojej aplikacji, która zawiera logikę biznesową, która określa, co iSchool obiekt do wystąpienia do różnych obiektów IStudent.

Tak więc dla prostych klas (obiektów wartości itp.) Konstruktor jest w porządku (nie chcemy przesadzać z aplikacją), ale w przypadku skomplikowanych hierarchii klas metoda fabryczna jest preferowana.

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

+1

Nawet jeśli uważasz, że jest to prosta klasa, istnieje szansa, że ​​ktoś musi rozszerzyć swoją prostą klasę, więc metoda fabryczna jest jeszcze lepsza. Na przykład. możesz zacząć od ElementarySchool, ale później ktoś (włączając Ciebie) może rozszerzyć go o PrivateElementarySchool i PublicElementarySchool. – jack

+5

to powinna być zaakceptowana odpowiedź. – am05mhz

+1

@David, dobra odpowiedź, ale czy możesz rozwinąć na przykładzie, gdzie każda implementacja interfejsu może wymagać różnych parametrów dla konstrukcji. Oto głupi przykład: "kanapka z IFOD = nowa kanapka (ser chz, mięso mięsne);" i "zupa z jadłospisu = nowa zupa (bulion z rosołem, warzywa warzywne)" Jak może tu pomóc fabryka i budowniczy? –

11

Używaj fabryki tylko wtedy, gdy potrzebujesz dodatkowej kontroli przy tworzeniu obiektu, w sposób niemożliwy do wykonania z konstruktorami.

Fabryki mają na przykład możliwość buforowania.

Innym sposobem wykorzystania fabryk jest scenariusz, w którym nie znasz typu, który chcesz zbudować. Często widzisz ten typ użycia w scenariuszach fabrycznych wtyczek, gdzie każda wtyczka musi wywodzić się z klasy bazowej lub implementować jakiś interfejs. Fabryka tworzy wystąpienia klas wywodzących się z klasy podstawowej lub implementujących interfejs.

54

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

statyczne metody fabryki zalety:

  1. Mają imiona.
  2. Nie są wymagane tworzenie nowego obiektu za każdym razem, gdy są wywoływane.
  3. Mogą zwrócić obiekt dowolnego podtypu zwracanego typu.
  4. Redukują szczegółowość tworzenia instancji typów parametryzowanych.

statyczne metody fabryczne wady:

  1. Przy udzielaniu tylko statyczne metody fabryki, zajęcia bez konstruktorów publicznych lub chronionych nie można podklasy.
  2. te nie są łatwe do odróżnienia od innych metod statycznych
+3

To wydaje mi się raczej poważnym błędem w Javie, a następnie ogólnym problemem OOD. Istnieje wiele języków OO, które nie mają * * konstruktorów, ale podklasowanie działa dobrze. –

+0

@cherouvim dlaczego w większości przypadków kod jest zapisywany za pomocą Konstruktorów, jeśli '(metody fabryczne są lepsze niż konstruktory. (Element-1)) Efektywna java' – UnKnown

+0

Dobre punkty. Jest to jednak specyficzne dla Javy. Sprawa może dotyczyć funkcji językowej, która odróżnia metody fabryczne od innych metod statycznych. – OCDev

6

Konkretny przykład z aplikacji CAD/CAM.

Ścieżkę cięcia można wykonać za pomocą konstruktora. Jest to seria linii i łuków określających ścieżkę cięcia. Podczas gdy serie linii i łuków mogą być różne i mają różne współrzędne, można je łatwo obsłużyć, przekazując listę do konstruktora.

Kształt byłby wykonany przy użyciu fabryki. Ponieważ podczas gdy istnieje klasa kształtu, każdy kształt będzie różnie ustawiony w zależności od tego, jaki jest kształt. Nie wiemy, jaki kształt będziemy inicjować, dopóki użytkownik nie dokona wyboru.

11

Cytat z "Efektywna Java", wydanie 2, poz. 1: Rozważ statyczne metody fabryczne zamiast konstruktorów, str. 5:

„Zauważ, że statyczną metodą fabryka nie jest taki sam, jak wzorzec Factory Method z Design Patterns [Gamma95, str. 107] Statyczna metoda fabrycznie opisany w pozycja ta nie ma bezpośredniego odpowiednika w. Wzorce projektowe."

3

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

Proces ten zdecydowanie powinien znajdować się poza konstruktorem.

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

  2. Zadaniem i powodem konstruktora jest członków danych initialize i ustanowić klasy niezmienny użyciu wartości przekazywane do konstruktora.

  3. Na wszystko jeszcze lepszym rozwiązaniem jest użycie statycznej metody fabryki lub w bardziej złożonych przypadkach oddzielny fabrycznego lub budowniczy klasa.

Some constructor guide lines from Microsoft:

Czy minimalną pracę w konstruktorze. Konstruktory nie powinny wykonywać wiele innych zadań niż przechwytywanie parametrów konstruktora. Koszt jakiegokolwiek innego przetwarzania powinien zostać opóźniony, dopóki nie będzie to wymagane.

I

Rozważ użycie statycznej metody fabryki zamiast konstruktora czy semantyka żądanej operacji nie map bezpośrednio do budowy nowej instancji.

Powiązane problemy