Jaki jest preferowany sposób inicjowania klas podczas modelowania klas:
- Konstruktory lub
- Metody fabryczne
A jakie byłyby względy korzystania z jednego z nich?
W niektórych sytuacjach wolę metodę fabryczną, która zwraca null, jeśli obiektu nie można zbudować. To czyni kod porządnym. Mogę po prostu sprawdzić, czy zwrócona wartość nie jest pusta przed podjęciem alternatywnej akcji, w przeciwieństwie do zgłoszenia wyjątku od konstruktora. (Osobiście nie lubię wyjątków)
Powiedzmy, że mam konstruktor klasy, który oczekuje wartości id. Konstruktor używa tej wartości do wypełnienia klasy z bazy danych. W przypadku, gdy rekord o podanym identyfikatorze nie istnieje, konstruktor zgłasza wyjątek RecordNotFoundException. W takim przypadku będę musiał zawrzeć konstrukcję wszystkich takich klas w bloku try..catch.
W przeciwieństwie do tego mogę zastosować statyczną metodę fabryczną na tych klasach, które zwrócą null, jeśli rekord nie zostanie znaleziony.
Które podejście jest lepsze w tym przypadku, w przypadku metody konstruktora lub fabryki?
Zapytaj siebie, czym one są i dlaczego je mamy. Oba są po to, aby utworzyć instancję obiektu.
Jak dotąd bez różnicy. Teraz wyobraźmy sobie, że mamy różne typy szkół i chcemy przejść z używania ElementarySchool na HighSchool (która pochodzi z ElementarySchool lub implementuje ten sam interfejs ISchool co ElementarySchool). Zmiana kodu wyglądałaby następująco:
W przypadku interfejsu mielibyśmy:
Teraz, jeśli masz ten kod w wielu miejscach, możesz zobaczyć, że użycie metody fabrycznej może być dość tanie, ponieważ po zmianie metody fabrycznej jest to gotowe (jeśli użyjemy drugiego przykładu z interfejsami).
I to jest główna różnica i przewaga. Gdy zaczniesz zajmować się złożonymi hierarchiami klas i chcesz dynamicznie utworzyć instancję klasy z takiej hierarchii, otrzymasz następujący kod. Metody fabryczne mogą następnie przyjąć parametr, który mówi metodzie, jaką konkretną instancję należy utworzyć. Załóżmy, że masz klasę MyStudent i musisz utworzyć instancję odpowiedniego obiektu ISchool, aby Twój uczeń był członkiem tej szkoły.
Teraz masz w aplikacji jedno miejsce, które zawiera logikę biznesową, która określa, który obiekt ISchool ma zostać utworzony dla różnych obiektów IStudent.
Tak więc - dla prostych klas (obiektów wartości itp.) Konstruktor jest w porządku (nie chcesz przeceniać swojej aplikacji), ale w przypadku złożonych hierarchii klas preferowaną metodą jest metoda fabryczna.
W ten sposób postępujesz zgodnie z pierwszą zasadą projektowania od grupy czterech książek „Program do interfejsu, a nie implementacja”.
źródło
IFood sandwich = new Sandwich(Cheese chz, Meat meat);
i WIFood soup = new Soup(Broth broth, Vegetable veg);
jaki sposób fabryka i / lub konstruktor mogą tutaj pomóc?Musisz przeczytać (jeśli masz dostęp) Efektywna Java 2 pozycja 1: Rozważ statyczne metody fabryczne zamiast konstruktorów .
Zalety statycznych metod fabrycznych:
Wady statycznych metod fabrycznych:
źródło
( factory methods are better than Constructors. ( Item-1 ) ) Effective java
Domyślnie preferowane są konstruktory, ponieważ są łatwiejsze do zrozumienia i napisania. Jeśli jednak chcesz oddzielić subtelności konstrukcyjne obiektu od jego semantycznego znaczenia w rozumieniu kodu klienta, lepiej skorzystaj z fabryk.
Różnica między konstruktorami a fabrykami jest analogiczna do, powiedzmy, zmiennej i wskaźnika do zmiennej. Istnieje inny poziom pośredni, co jest wadą; ale jest też inny poziom elastyczności, co jest zaletą. Dokonując wyboru, dobrze byłoby dokonać analizy kosztów w porównaniu do korzyści.
źródło
Używaj fabryki tylko wtedy, gdy potrzebujesz dodatkowej kontroli przy tworzeniu obiektów, w sposób niemożliwy do osiągnięcia w przypadku konstruktorów.
Fabryki mają na przykład możliwość buforowania.
Innym sposobem korzystania z fabryk jest scenariusz, w którym nie znasz typu, który chcesz zbudować. Często ten typ użycia występuje w scenariuszach fabryk wtyczek, w których każda wtyczka musi pochodzić z klasy podstawowej lub implementować jakiś interfejs. Fabryka tworzy instancje klas, które wywodzą się z klasy podstawowej lub implementują interfejs.
źródło
Cytat z „Effective Java”, wyd. 2, poz. 1: Rozważ statyczne metody fabryczne zamiast konstruktorów, str. 5:
„Zauważ, że statyczna metoda fabryczna nie jest taka sama jak wzorzec metody fabrycznej z wzorców projektowych [Gamma95, s. 107]. Statyczna metoda fabryczna opisana w tym punkcie nie ma bezpośredniego odpowiednika we wzorach projektowych”.
źródło
Oprócz „skutecznej javy” (jak wspomniano w innej odpowiedzi) inna klasyczna książka sugeruje również:
Na przykład. nie pisz
ale zamiast tego pisz
Książka posuwa się tak daleko, że sugeruje uczynienie
Complex(float)
konstruktora prywatnym, aby zmusić użytkownika do wywołania metody fabryki statycznej.źródło
from…
,to…
,parse…
,with…
, i tak dalej. Należy pamiętać, że klasy java.time są zbudowane tak, aby były niezmienne, ale niektóre z tych konwencji nazewnictwa mogą być przydatne również w przypadku klas zmiennych.Konkretny przykład z aplikacji CAD / CAM.
Ścieżkę cięcia wykonano by przy użyciu konstruktora. Jest to szereg linii i łuków określających ścieżkę do wycięcia. Chociaż seria linii i łuków może być różna i mieć różne współrzędne, łatwo ją obsłużyć, przekazując listę do konstruktora.
Kształt zostałby wykonany przy użyciu fabryki. Ponieważ podczas gdy istnieje klasa kształtu, każdy kształt będzie konfigurowany inaczej w zależności od typu kształtu. Nie wiemy, jaki kształt będziemy inicjalizować, dopóki użytkownik nie dokona wyboru.
źródło
Ten proces zdecydowanie powinien znajdować się poza konstruktorem.
Konstruktor nie powinien uzyskiwać dostępu do bazy danych.
Zadaniem i powodem dla konstruktora jest inicjalizacja elementów danych i ustanowienie niezmiennika klasy za pomocą wartości przekazanych do konstruktora.
W przypadku wszystkiego innego lepszym podejściem jest zastosowanie statycznej metody fabrycznej lub w bardziej złożonych przypadkach oddzielnej klasy fabryki lub producenta .
Niektóre linie przewodnika konstruktora od Microsoft :
I
źródło
Czasami musisz sprawdzić / obliczyć niektóre wartości / warunki podczas tworzenia obiektu. A jeśli może rzucić wyjątek - konstrukcja jest bardzo zła. Musisz więc zrobić coś takiego:
Gdzie wszystkie dodatkowe obliczenia są w init (). Ale tylko Ty jako programista naprawdę wiesz o tej 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, ukrywając tę init () przed bezpośrednim wywołaniem - więc nie ma problemów. Dzięki takiemu podejściu nie ma problemów z upadkiem na tworzenie i wyciek pamięci.
Ktoś powiedział ci o buforowaniu. To jest dobre. Ale musisz również pamiętać o wzorze Flyweight, który jest przyjemny w użyciu w stylu Factory.
źródło