12

Czytałem Skuteczne Java przez Joshua Bloch i do tej pory naprawdę zasługuje na swoją reputację. Pierwszy element stanowi przekonujący przypadek dla statycznych metod konstruowania przez ponad konstruktorów. Tak bardzo, że zacząłem kwestionować ważność dobrych starych konstruktorów :).Czy kiedykolwiek wolimy konstruktorów od metod statycznych w fabrykach? Jeśli tak, to kiedy?

zalety/wady z książki są zestawione poniżej:

Zalety:

  1. Mają imiona!
  2. Mamy całkowitą kontrolę przykład (Singleton'y, wydajność itd.)
  3. Mogą zwrócić podtypu/interfejs
  4. kompilator zapewni wnioskowanie typu

wady:

  1. Klasy prywatne nie mogą być poddane podklasie
  2. Nie wyróżniają się w dokumentacji jako konstruktor s zrobić

Pierwszą wadą może być rzeczywiście A Good Thing (jak wspomniano w książce). Druga, myślę, jest tylko niewielką wadą i może być łatwo rozwiązana w nadchodzących wydaniach java (adnotacje dla javadoc itp.).

Wygląda na to, że w końcu metody fabryki mają prawie wszystkie zalety konstruktorów, wiele wiele więcej zalet i brak realnych wad!

Więc moje pytanie jest w zasadzie w trzech częściach:

  1. Czy to dobra praktyka, aby zawsze używać statycznych metod fabrycznych domyślnie przez konstruktorów?
  2. Czy korzystanie z konstruktorów jest uzasadnione?
  3. Dlaczego języki obiektowe nie zapewniają obsługi poziomu języka w fabrykach?

Uwaga: Istnieją dwa podobne pytania: When to use a Constructor and when to use getInstance() method (static factory methods)? i Creation of Objects: Constructors or Static Factory Methods. Jednak odpowiedzi albo podają powyższą listę, albo powtarzają uzasadnienie statycznych metod fabrycznych, o których już wiem.

+0

Ponadto, podobno fabryki mają nawet zalety związane z bezpieczeństwem gwintów w stosunku do konstruktorów zgodnie z [to] (http://madpropellerhead.com/random/20100328-java-final-fields-are-not-as-final-as- możesz pomyśleć). – MadChuckle

+0

Przeczytałem artykuł, do którego się odwołałem, ale doszedłem do przeciwnego wniosku jak autor ... :-) Widzę, co zostało wskazane, ale się nie zgadzam. Być może ma to związek z konkretnymi przypadkami użycia, które zwykle widzimy podczas kodowania. –

+0

@BrianKnoblauch, nie jestem ekspertem w dziedzinie współbieżności, więc przyjmiemy twoje słowo, ponieważ przykłady wydają się nieco spreparowane :) – MadChuckle

Odpowiedz

7

statyczne fabryki nadal muszą wywołać konstruktora na końcu. Możesz przenieść większość funkcji do statycznej fabryki, ale nie możesz uniknąć użycia konstruktora.

Z drugiej strony dla prostych spraw można mieć tylko konstruktora bez statycznej fabryki.

Konstruktory to jedyny sposób na ustawienie pól końcowych, które preferują IMHO w stosunku do pól nieostatnich.

Można używać konstruktorów w podklasach. Nie można używać fabryk statycznych dla podklasy.

Jeśli masz dobry schemat wtrysku zależności, aby zbudować zależności komponentu, może się okazać, że statyczne fabryki nie dodają wiele.

+0

Oczywiście, że fabryki używają konstruktorów za kulisami i dlatego włączyłem trzecie pytanie. A fabryki mogą ustawiać ostateczne pola za pomocą konstruktorów. Nie rozumiem ograniczeń podklasowych, o których wspomniałeś; Możesz rozwinąć temat? – MadChuckle

+0

OK, wygląda na to, że mówisz o pierwszej wadzie; ale może jesteśmy w stanie dostarczyć fabrykom "poza" fabryki? – MadChuckle

+0

"Konstruktory to jedyny sposób ustawiania pól końcowych, które są preferowane przez IMHO do pól nieostatnich." To prawo jest wielki powód. Statyczne metody fabryczne prowadzą ścieżkę, która sprawia, że ​​gwintowanie jest trudne. Końcowe pola są dobrym początkiem w kierunku (wymuszonej) niezmienności i przyjazności wątków. W tym wielordzeniowym świecie przesunięcie wraca do konstruktorów i od fabryk. –

3

podoba mi się komentarz od jednego z podobnych pytań wyróżnionych:

(w jaki sposób zdecydować, czy należy faworyzować metody fabryki nad konstruktora),

„Trzeba zdecydować, co” Albo nie chcesz, żeby ludzie dzwonili do twojego konstruktora (tworzysz singleton lub fabrykę), albo nie masz nic przeciwko (jak w NumberFormat powyżej, gdzie inicjują niektóre obiekty dla wygody osoby dzwoniącej) "

Dla mnie oznacza to, że jest uzasadnione używaj konstruktora, gdzie metoda fabryczna nie jest wymagana. Bez potrzeby posiadania fabryki, po prostu sprawia, że ​​kod jest trudniejszy w śledzeniu ("która dokładnie podklasa jest tu zwrócona?")

+2

Czekaj. Ale częścią tego jest to, że osoba dzwoniąca nie powinna zwracać uwagi na to, jaka dokładnie podklasa jest zwracana, i możesz zmienić, która dokładnie podklasa jest zwracana bez konieczności zmiany twoich rozmówców. –

+0

To prawda, ale jeśli te podklasy implementują ten interfejs API na różne sposoby, prawdopodobnie będziesz musiał sprawdzić, która dokładnie podklasa jest zwracana, próbując wyśledzić problemy w kodzie. W tych okolicznościach uważam, że metody fabryczne zaciemniają rzeczy. –

+0

@ Disco3: Legalna metoda fabryczna powinna zwracać coś, czego metody będą się zachowywać, z perspektywy * rozmówcy *, tak jak klasa rodzica, ale to nie znaczy, że zachowanie wewnętrzne musiałoby się zgadzać. Na przykład, jeśli 'String' był wewnętrznie dziedziczony, konkatenacja łańcuchów, gdy jeden lub więcej przekroczy 256 znaków, może zwrócić obiekt' ConcatenatedString', który mógłby pomieścić tablicę odniesień do mniejszych ciągów. Wszystkie metody 'ConcatenatedString' dałyby taki sam rezultat, jak ciąg znaków zawierający wszystkie znaki z oryginałów, ale ... – supercat

3

Jestem w dość silnej zgodzie z Josh Bloch tutaj, a on sprawia, że ​​sprawa jest lepsza niż mogłem, ale tutaj jest kilka miejsc, w których statyczne fabryki nie są odpowiednie:

  • Gdy zastrzyk zależności jest bardziej sensowny; Systemy DI (na pewno Guice) mają skłonność do wstrzykiwania rzeczy przez swoich konstruktorów. W szczególności DI jest odpowiedni, gdy spodziewasz się, że parametry konstruktora mogą się zmienić w przyszłości.
  • Kiedy specjalnie chcesz, aby ludzie pisali podklasy, a ty zapewniasz szkielet do ich implementacji.
+0

Dobre punkty! Chociaż systemy DI mogą być również wdrażane według fabrycznego wzorca z pewnymi zaletami (), staram się zgodzić z tobą w tej sprawie. – MadChuckle

+0

O ile system DI, który zna się tylko na konstruktorach, będzie ograniczony do używania konstruktorów, i który oczekuje, że statyczne metody fabryczne o konkretnej nazwie będą ograniczone do klas za pomocą metody o tej nazwie, czy konstruktorzy oferują szczególne korzyści z perspektywy DI? Konstruktory * public * oferują wszelkie zalety podklas w stosunku do metod fabrycznych (z pewnością do konstrukcji podklasy potrzebne byłyby chronione konstruktory). – supercat

0

Konstruktorzy są nudni, wiesz dokładnie, gdzie ich szukać, znasz ich zakres, są w jakiś sposób przewidywalne. Są tam po to, aby samemu skonstruować obiekt, a nie wykonywać podobne do Boga zadania. Jeśli robisz zbyt wiele innych rzeczy, które nie mają wiele wspólnego z konstruowaniem obiektu, wiesz, że robisz coś źle. I nie można tego "wyleczyć", zmieniając nazwę metody. Są więc bardziej skupieni, "lepsi" w jakości kodu, kiedy nie ma się najlepszych programistów. (Kiedy masz te ostatnie, wspomniane przeze mnie punkty nie mają znaczenia.)

Nudne rzeczy. Zróbmy coś więcej przyjemności i intelektualnego wyzwania ...

Tylko dla zapisów: nie zaniedbuję punktów wymienionych w pytaniu i innych odpowiedzi, chciałem tylko dodać ten dodatkowy punkt.

Powiązane problemy