Wzorzec fabryczny (a przynajmniej użycie FactoryFactory..
) to podstawa wielu żartów, jak tutaj .
Oprócz posiadania pełnych i „kreatywnych” nazw, takich jak RequestProcessorFactoryFactory.RequestProcessorFactory , czy jest coś zasadniczo nie tak z wzorcem fabrycznym, jeśli musisz programować w Javie / C ++ i istnieje przypadek użycia dla Abstract_factory_pattern ?
W jaki sposób inny popularny język (na przykład Ruby lub Scala ) unikałby używania go podczas zarządzania podobną złożonością?
Pytam dlatego, że widzę głównie krytykę fabryk wymienionych w kontekście ekosystemu Java / Java EE , ale nigdy nie wyjaśniają, w jaki sposób rozwiązują je inne języki / frameworki.
java
design-patterns
senseiwu
źródło
źródło
Odpowiedzi:
Twoje pytanie jest oznaczone literą „Java”, nie jest zaskoczeniem, że pytasz, dlaczego szydzi się wzór Factory: sama Java zawiera ładnie zapakowane nadużycia tego wzoru.
Na przykład spróbuj załadować dokument XML z pliku i uruchom dla niego zapytanie XPath. Potrzebujesz tylko 10 linii kodu, aby skonfigurować Fabryki i Konstruktory:
Zastanawiam się, czy faceci, którzy zaprojektowali ten interfejs API, pracowali kiedyś jako programiści, czy po prostu czytali książki i rozrzucali. Rozumiem, że po prostu nie chcieli sami napisać parsera i zostawili to zadanie innym, ale nadal stanowi to brzydką implementację.
Ponieważ pytasz, jaka jest alternatywa, tutaj jest ładowanie pliku XML w C #:
Podejrzewam, że nowopowstali deweloperzy Java widzą szaleństwo Factory i myślę, że jest to w porządku - jeśli geniusze, którzy sami zbudowali Javę, tak często ich używali.
Fabryczne i wszelkie inne wzory są narzędziami, z których każde nadaje się do określonego zadania. Jeśli zastosujesz je do zadań, które nie są odpowiednie, na pewno będziesz mieć brzydki kod.
źródło
XmlDocument xml = new XmlDocument(); xml.Load("c:\\employees.xml"); XmlNodeList nodes = xml.SelectNodes(expression);
(Ogólnie rzecz biorąc, LINQ to XML jest znacznie łatwiejszy w użyciu, choć głównie w innych obszarach.) A oto artykuł z bazy wiedzy Znalazłem metodę zalecaną przez MS: support.microsoft.com/kb/308333Jak często ludzie nie rozumieją, co się dzieje (i obejmuje to wielu śmiechów).
To nie jest wzór fabryczny, który jest tak zły, jak to, że używa go wiele (może nawet większość) ludzi.
I to bez wątpienia wynika ze sposobu uczenia się programowania (i wzorców). Schoolkids (często nazywając siebie „studentami”) otrzymują polecenie „tworzenia X za pomocą wzorca Y” i po kilku iteracjach tej myśli, że jest to sposób na rozwiązanie każdego problemu programistycznego.
Dlatego zaczynają stosować określony wzór, który im się podoba w szkole, przeciw wszystkim i wszystkim, niezależnie od tego, czy jest to właściwe, czy nie.
Dotyczy to również profesorów uniwersyteckich, którzy piszą książki o projektowaniu oprogramowania.
Kulminacją tego był system, który z wyraźnym niezadowoleniem musiałem utrzymywać, który został stworzony przez jednego z nich (mężczyzna miał nawet kilka książek o projektowaniu obiektowym do swojego imienia i stanowisko nauczyciela na wydziale CS dużego uniwersytetu ).
Oparty był na układzie trójwarstwowym, przy czym każdy poziom sam układ trójwarstwowy (trzeba oddzielić ...). Na interfejsie między każdym zestawem warstw, po obu stronach, znajdowała się fabryka produkująca obiekty do przesyłania danych do drugiej warstwy oraz fabryka produkująca obiekt do tłumaczenia otrzymanego obiektu na jeden należący do warstwy odbiorczej.
Dla każdej fabryki istniała abstrakcyjna fabryka (kto wie, fabryka może się zmienić, a wtedy nie chcesz, aby kod wywołujący musiał się zmienić ...).
I cały ten bałagan był oczywiście całkowicie nieudokumentowany.
System miał bazę danych znormalizowaną do 5. normalnej postaci (nie żartuję).
System, który był zasadniczo niewiele więcej niż książką adresową, której można używać do rejestrowania i śledzenia dokumentów przychodzących i wychodzących, miał 100 MB bazy kodów w C ++ i ponad 50 tabel baz danych. Drukowanie 500 listów zajęłoby 72 godziny przy użyciu drukarki podłączonej bezpośrednio do komputera z oprogramowaniem.
Oto dlaczego ludzie szydzą z wzorców, a konkretnie z ludzi skupiających się pojedynczo na jednym konkretnym wzorze.
źródło
Fabryki mają wiele zalet, które pozwalają na eleganckie projekty aplikacji w niektórych sytuacjach. Jednym z nich jest to, że możesz ustawić właściwości obiektów, które później chcesz utworzyć w jednym miejscu, tworząc fabrykę, a następnie przekazując tę fabrykę. Ale często tak naprawdę nie musisz tego robić. W takim przypadku użycie fabryki tylko zwiększa złożoność, nie dając ci nic w zamian. Weźmy na przykład tę fabrykę:
Jedną z alternatyw dla wzorca fabrycznego jest bardzo podobny wzorzec konstruktora. Główna różnica polega na tym, że właściwości obiektów utworzonych przez fabrykę są ustawiane podczas inicjalizacji fabryki, podczas gdy program budowniczy jest inicjowany z domyślnym stanem, a wszystkie właściwości są ustawiane później.
Ale kiedy problemem jest nadinżynieria, zastąpienie fabryki konstruktorem prawdopodobnie nie stanowi znacznej poprawy.
Najprostszym zamiennikiem dla każdego wzorca jest oczywiście tworzenie instancji obiektów za pomocą prostego konstruktora z
new
operatorem:Konstruktory mają jednak istotną wadę w większości języków zorientowanych obiektowo: muszą zwracać obiekt dokładnie tej klasy i nie mogą zwracać podtypu.
Jeśli musisz wybrać podtyp w czasie wykonywania, ale nie chcesz do tego tworzyć zupełnie nowej klasy Builder lub Factory, możesz zamiast tego użyć metody factory. Jest to statyczna metoda klasy, która zwraca nowe instancje tej klasy lub jednej z jej podklas. Fabrykę, która nie utrzymuje żadnego stanu wewnętrznego, często można zastąpić taką metodą fabryczną:
Nową funkcją w Javie 8 są odwołania do metod, które umożliwiają przekazywanie metod, tak jak w przypadku fabryki bezstanowej. Dogodnie wszystko, co akceptuje odwołanie do metody, akceptuje również każdy obiekt, który implementuje ten sam interfejs funkcjonalny, którym może być również pełnoprawna Fabryka ze stanem wewnętrznym, dzięki czemu można łatwo wprowadzić fabryki później, gdy zobaczy się powód.
źródło
foo = new Bar(23);
to równoważnefoo = Bar._createInstance(23);
. Obiekt powinien mieć możliwość wiarygodnego zapytania własnego typu przy użyciugetRealType()
metody prywatnej , ale obiekty powinny mieć możliwość wyznaczenia nadtypu, który ma zostać zwrócony przez wywołania zewnętrzne dogetType()
. Kod zewnętrzny nie powinien dbać o to, czy wywołanienew String("A")
faktycznie zwraca instancjęString
[w przeciwieństwie do np. InstancjiSingleCharacterString
].draw(OutputStream out)
ale generują nieco inny HTML, fabryka metod statycznych tworzy odpowiednią klasę dla danej sytuacji, a następnie wywołujący może po prostu użyć metody rysowania.[[SomeClass alloc] init]
. Możliwe jest zwrócenie instancji zupełnie innej klasy lub innego obiektu (takiego jak wartość z pamięci podręcznej)Fabryki tego lub innego rodzaju znajdują się w prawie każdym języku obiektowym w odpowiednich okolicznościach. Czasami po prostu potrzebujesz sposobu, aby wybrać rodzaj obiektu do utworzenia na podstawie prostego parametru, takiego jak ciąg.
Niektórzy ludzie posuwają się za daleko i próbują zaprojektować swój kod, aby nigdy nie trzeba było wywoływać konstruktora, z wyjątkiem wewnątrz fabryki. Rzeczy zaczynają być absurdalne, gdy masz fabryki.
Uderzyło mnie, gdy nauczyłem się Scali i nie znam Ruby, ale wierzę, że jest tak samo, ponieważ język jest na tyle wyrazisty, że programiści nie zawsze próbują przesunąć pracę „hydrauliczną” do zewnętrznych plików konfiguracyjnych . Zamiast skłaniać się do tworzenia fabryk fabrycznych, aby połączyć swoje klasy w różne konfiguracje, w Scali używasz obiektów z pomieszanymi cechami. Stosunkowo proste jest również tworzenie prostych języków DSL w języku do zadań, które są często zbyt zaawansowane w Javie.
Ponadto, jak zauważyły inne komentarze i odpowiedzi, zamknięcia i funkcje pierwszej klasy eliminują potrzebę wielu wzorów. Z tego powodu uważam, że wiele anty-wzorów zacznie zanikać, gdy C ++ 11 i Java 8 zostaną powszechnie przyjęte.
źródło
Ogólnie rzecz biorąc, istnieje tendencja, że programy Java są strasznie przeprojektowane [potrzebne źródło]. Posiadanie wielu fabryk jest jednym z najczęstszych objawów nadmiernej inżynierii; dlatego ludzie się z nich śmieją.
W szczególności problem Javy związany z fabrykami polega na tym, że w Javie a) konstruktory nie są funkcjami i b) funkcje nie są pierwszorzędnymi obywatelami.
Wyobraź sobie, że możesz napisać coś takiego (niech
Function
będzie dobrze znanym interfejsem środowiska JRE )Zobacz, brak interfejsów lub klas fabrycznych. Wiele dynamicznych języków ma pierwszorzędne funkcje. Niestety, nie jest to możliwe w Javie 7 lub wcześniejszej (wdrożenie tego samego w fabrykach pozostawia się czytelnikowi).
Alternatywą jest więc nie tyle „użycie innego wzorca”, ale więcej „użycie języka z lepszym modelem obiektowym” lub „nie nadużywanie prostych problemów”.
źródło