Dlaczego potrzebujemy abstrakcyjnego wzorca projektowego fabryki?

124

Większość definicji mówi:

Fabryka abstrakcyjna zapewnia interfejs do tworzenia rodzin powiązanych obiektów bez określania ich konkretnych klas

Jaki jest pożytek z Abstract Factory Pattern, skoro możemy osiągnąć to poprzez stworzenie samego obiektu konkretnej klasy. Po co nam metoda fabryki, która tworzy obiekt klasy Concrete?

Proszę podać mi przykład z życia, w którym muszę zaimplementować wzorzec abstractFactory?

Amit
źródło

Odpowiedzi:

218

Abstract Factory to centralny wzorzec projektowy dla Dependency Injection (DI). Oto lista pytań związanych z przepełnieniem stosu, w przypadku których zaakceptowano rozwiązanie Abstract Factory .

Zgodnie z moim najlepszym zrozumieniem, te pytania przedstawiają rzeczywiste obawy lub problemy, które mieli ludzie, więc powinieneś zacząć od kilku przykładów z życia:

Mark Seemann
źródło
6
Wszystkie te przykłady opisują wzorzec metody fabrycznej, ponieważ wszystkie zwracają interfejs pojedynczego produktu. Żaden z nich nie jest abstrakcyjnym wzorcem fabrycznym, ponieważ żaden z nich nie tworzy rodziny powiązanych interfejsów produktów.
jaco0646
32
W celu pełnego ujawnienia, autor tej odpowiedzi powinien był wyjaśnić, że jest on również autorem każdej z połączonych odpowiedzi; więc ta lista NIE jest reprezentatywną próbką ze społeczności SO.
jaco0646
1
@ jaco0646 IIRC, wzorzec Factory Method to specjalizacja wzorca Template Method , który opiera się na dziedziczeniu. Mogę się jednak mylić, ponieważ obecnie podróżuję i nie mam ze sobą książki GoF. Co masz na myśli, mówiąc „żaden z nich nie tworzy rodziny powiązanych interfejsów produktów”?
Mark Seemann,
1
Najprostszą wskazówką, która wskazuje, że fabryka nie jest zgodna ze wzorcem fabryki abstrakcyjnej, jest policzenie abstrakcyjnych produktów wytwarzanych przez fabrykę (użyłem terminu „interfejsy produktu” zamiast „produktów abstrakcyjnych”, aby uniknąć nadużywania słowa „abstrakcja”) . Fabryka produkująca pojedynczy produkt abstrakcyjny nie może być fabryką abstrakcyjną, ponieważ z definicji fabryka abstrakcyjna produkuje rodzinę produktów pokrewnych . Należy pamiętać, że ta rodzina nie odnosi się do różnych implementacji jednego interfejsu, ale raczej do produktów z różnymi, powiązanymi interfejsami.
jaco0646
1
Oto przykład oodesign.com/abstract-factory-pattern.html . Po to pierwotnie powstał abstrakcyjny wzór fabryki.
user2802557
23

Przykładem z życia wzorca Abstract Factory jest zapewnienie dostępu do danych do dwóch różnych źródeł danych. Załóżmy, że Twoja aplikacja obsługuje różne magazyny danych. (np. baza danych SQL i plik XML). Masz dwa różne interfejsy dostępu do danych, np. IReadableStoreI IWritableStoredefiniujące typowe metody oczekiwane przez Twoją aplikację, niezależnie od typu używanego źródła danych.

Rodzaj źródła danych nie powinien zmieniać sposobu, w jaki kod klienta pobiera klasy dostępu do danych. Twój AbstractDataAccessFactorywie, który jest skonfigurowany typ źródła danych i dostarcza beton fabryczne dla kodu klienta, czyli SqlDataAccessFactoryalbo XmlDataAccessFactory. Te fabryki betonu można tworzyć konkretne implementacjach, np SqlReadableStorea SqlWriteableStore.

DbProviderFactory w .NET Framework jest przykładem tego wzorca.

Johannes Rudolph
źródło
18
Ta odpowiedź może dokładnie opisać wzorzec Metody Fabryki lub Wzorzec Fabryki Statycznej, ale nie model Fabryki Abstrakcyjnej.
jaco0646
5

Jeśli dobrze rozumiem - pytanie brzmi, dlaczego mamy zarówno metodę Factory, jak i abstrakcyjne wzorce fabryczne. Fabryka abstrakcyjna jest potrzebna, gdy różne klasy polimorficzne mają różne procedury tworzenia instancji. I chcesz, aby jakiś moduł tworzył instancje i używał ich bez znajomości szczegółów inicjalizacji obiektu. Na przykład - chcesz utworzyć obiekty Java, wykonując jakieś obliczenia. Ale niektóre z nich są częścią aplikacji, podczas gdy kod bajtowy innych powinien być odczytywany z bazy danych. Z drugiej strony - po co nam metoda fabryczna? Zgadzam się, ta abstrakcyjna fabryka nakłada się na to. Ale w niektórych przypadkach - jest znacznie mniej kodu do napisania, posiadanie mniejszej liczby klas i interfejsów sprawia, że ​​system jest łatwiejszy do zrozumienia.

David Gruzman
źródło
4

Jaki jest pożytek z Abstract Factory Pattern, skoro możemy osiągnąć to poprzez stworzenie samego obiektu konkretnej klasy. Po co nam metoda fabryki, która tworzy obiekt klasy Concrete?

W przypadku braku Fabryki Abstrakcji Klient musi znać szczegóły konkretnych zajęć. To ścisłe połączenie zostało usunięte z Fabryką Abstrakcji .

Teraz Factory Method ujawnia kontrakt, z którego musi korzystać klient. Możesz dodać więcej produktów do swojej fabryki, dodając nowe produkty, które implementują interfejs ujawniony przez Factory Method.

Zapoznaj się z tymi powiązanymi pytaniami SE, aby lepiej zrozumieć:

Jaka jest podstawowa różnica między wzorcem fabrycznym a abstrakcyjnym wzorcem fabrycznym?

Zamiar:

Zapewnij interfejs do tworzenia rodzin powiązanych lub zależnych obiektów bez określania ich konkretnych klas.

Można zrozumieć intencji, budowa, kontrolna i zasady kciuka of Abstract Factory wzoru z tego sourcemaking artykułu.

Lista kontrolna:

  1. Zdecyduj, czy niezależność platformy i usługi tworzenia są obecnie źródłem bólu.
  2. Zaplanuj macierz platform i produktów .
  3. Zdefiniuj interfejs fabryki, który składa się z metody fabrycznej dla każdego produktu.
  4. Zdefiniuj klasę pochodną fabryki dla każdej platformy, która hermetyzuje wszystkie odwołania do nowego operatora.
  5. Klient powinien wycofać wszystkie odniesienia do nowego, i korzystać z metod fabryki do tworzenia produktów przedmiotów.
Ravindra babu
źródło
2

Fabryki abstrakcyjne doskonale nadają się do obsługi wielu platform, przy jednoczesnym zachowaniu ujednoliconej bazy kodu. Załóżmy, że masz duży program Qt lub GTK + lub .NET / Mono, który chcesz uruchomić w systemach Windows, Linux i OSX. Ale masz funkcję, która jest zaimplementowana w inny sposób na każdej platformie (być może przez API kernel32 lub funkcję POSIX).

public abstract class Feature
{
    public abstract int PlatformSpecificValue { get; }

    public static Feature PlatformFeature
    {
        get
        {
            string platform;
            // do platform detection here
            if (platform == "Win32")
                return new Win32Feature();
            if (platform == "POSIX")
                return new POSIXFeature();
        }
    }

    // platform overrides omitted
}

Dzięki tej fabryce abstrakcyjnej Twój interfejs użytkownika nie musi nic wiedzieć o bieżącej platformie.

Feature feature = Feature.PlatformFeature;
Console.WriteLine(feature.PlatformSpecificValue);
piedar
źródło
1
Nie rozumiem, czym różni się to od zwykłego używania metod fabrycznych do zwracania typu abstrakcyjnego, aby klient nie znał szczegółów implementacji?
kiwicomb123
1

Jeśli spojrzysz na wzorce projektowe, prawie wszystkie z nich mogą być zbędne. Ale jaki wzorzec oznacza powszechnie stosowane podejście do rozwiązania podobnego typu problemów. Wzorzec projektowy zapewnia podejście na poziomie projektu lub rozwiązanie zestawu podobnego typu problemu projektowego. Korzystanie ze wzorca projektowego pomaga rozwiązać problem, a tym samym szybciej dostarczać.

Kangkan
źródło
1

To proste, wyobrażając sobie, że masz kod, który działa z abstrakcją, powinieneś tworzyć abstrakcje, a nie konkretne klasy.

Zawsze powinieneś pracować przeciwko abstrakcjom, ponieważ możesz lepiej modyfikować kod.

To jest dobry przykład: http://en.wikipedia.org/wiki/Abstract_factory_pattern#C.23

Pablo Castilla
źródło
1

Uważam, że wzorzec Abstract Factory jest przereklamowany.

Po pierwsze, nie zdarza się tak często, że masz zestaw powiązanych ze sobą typów, które chcesz utworzyć.

Po drugie, poziom pośrednictwa (abstrakcji) zapewniany przez interfejsy zwykle wystarcza podczas pracy z iniekcją zależności.

Typowy przykład WindowsGui vs MacGui vs ..., w którym masz WindowsButton, MacButton, WindowsScrollBar, MacScrollbar itp., Jest często łatwiejszy do wdrożenia poprzez zdefiniowanie konkretnych przycisków, pasków przewijania itp. Przy użyciu wzorca Visitor i / lub Interpreter, aby zapewnić rzeczywiste zachowanie.

eljenso
źródło
ma określony cel. dzięki iniekcji zależności nie chcesz, aby lokalizatory usług znajdowały się dalej od złożonego katalogu głównego. zamiast tego używasz wstrzykniętej fabryki abstrakcyjnej.
Adam Tuliper - MSFT
2
cóż ... używanie lokalizatora usług z DI to antypatia. Fabryka abstrakcyjna to uniwersalne rozwiązanie, gdy potrzebujemy stworzyć ZALEŻNOŚCI z wartości uruchomieniowych.
TheMentor
1

Myślę, że jest miejsce na abstrakcyjny wzorzec fabryki zamiast prostego wzorca fabryki w miejscach, w których Twoje instancje są bardzo skomplikowane, zbyt skomplikowane i brzydkie dla pojedynczej fabryki i zbyt skomplikowane, aby interfejs użytkownika mógł je pojąć.

Powiedzmy, że jest to marka TYPE_A, a nie pojedyncza klasa ... powiedzmy, że istnieje rodzina 100 rodzajów podobnych klas typu A i musisz utworzyć z nich jeden obiekt. Wyobraź sobie, że istnieje szczegółowa, wyrafinowana informacja potrzebna do stworzenia właściwego obiektu z marki wielu podobnych typów obiektów, aw tej encji obiektu musisz dokładnie wiedzieć, które parametry należy dostroić i jak je dostroić.

W specjalnej fabryce dla tej marki będziemy musieli rozróżniać i pobierać dokładny obiekt do utworzenia wystąpienia, a także sposób jego utworzenia. będziemy wiedzieć, że na podstawie danych wejściowych z sieci (powiedzmy, jaki kolor jest dostępny w sklepie internetowym) oraz z innych aplikacji i usług działających w tle (parametry, których UI nie zna).

A może jutro będziemy mieć inną rodzinę, powiedzmy type_B i type_C, do utworzenia instancji. Więc interfejs użytkownika będzie miał „jeśli jeszcze”, aby wiedzieć, czy użytkownik chce „typ_A”, „typ_B” lub „typ_C” - ale klasy fabryk zdecydują dokładnie, którą klasę z typu (z rodziny) zbudować, i jak go dostroić - jakie wartości ustawić na jego parametry lub wysłać do kontrahenta. Wszystko to - według wielu parametrów, których interfejs użytkownika nie jest świadomy. To wszystko będzie za dużo dla jednej klasy fabryki.

Udi Reshef
źródło
1

Przykład z życia wzięty jest w przestrzeni nazw System.Data.Common, która ma abstrakcyjne klasy bazowe, które obejmują DbConnection, DbCommand i DbDataAdapter i są współużytkowane przez dostawców danych .NET Framework, takich jak System.Data.SqlClient i System.Data.OracleClient, które umożliwiają programiście pisanie ogólnego kodu dostępu do danych, który nie jest zależny od konkretnego dostawcy danych.

Klasa DbProviderFactories udostępnia statyczne metody tworzenia wystąpienia DbProviderFactory. Wystąpienie zwraca następnie poprawny obiekt o jednoznacznie określonym typie na podstawie informacji o dostawcy i parametrów połączenia podanych w czasie wykonywania.

Przykład:

 DataTable allProvidersTable = DbProviderFactories.GetFactoryClasses();

wprowadź opis obrazu tutaj

        /* Getting SqlClient family members */
        DbProviderFactory dbProviderFactory = DbProviderFactories.GetFactory("System.Data.SqlClient");
        DbCommand dbCommand = dbProviderFactory.CreateCommand();
        DbConnection dbConnection = dbProviderFactory.CreateConnection();
        DbDataAdapter dbDataAdapter = dbProviderFactory.CreateDataAdapter();

        SqlClientFactory sqlClientFactory = (SqlClientFactory)dbProviderFactory;
        SqlConnection sqlConnection = (SqlConnection)dbConnection;
        SqlCommand sqlCommand = (SqlCommand) dbCommand;
        SqlDataAdapter sqlDataAdapter = (SqlDataAdapter) dbDataAdapter;

        /* Getting OracleClient family members*/
        dbProviderFactory = DbProviderFactories.GetFactory("System.Data.OracleClient");
        dbCommand = dbProviderFactory.CreateCommand();
        dbConnection = dbProviderFactory.CreateConnection();
        dbDataAdapter = dbProviderFactory.CreateDataAdapter();

        OracleClientFactory oracleClientFactory = (OracleClientFactory)dbProviderFactory;
        OracleConnection oracleConnection = (OracleConnection)dbConnection;
        OracleCommand oracleCommand = (OracleCommand)dbCommand;
        OracleDataAdapter oracleDataAdapter = (OracleDataAdapter)dbDataAdapter;

Przykład-2 wprowadź opis obrazu tutaj

Architektura rozwiązania kodu wprowadź opis obrazu tutaj

Wystąpienia fabryki betonu są dostarczane przy użyciu statycznej metody fabryki, jak pokazano poniżej

public  class FurnitureProviderFactory
{
    public static IFurnitureFactory GetFactory(string furnitureType)
    {
        if (furnitureType == "Wood")
        {
            return new WoodenFurnitureFactory();
        }
        if (furnitureType == "Plastic")
        {
            return new PlasticFurnitureFactory();
        }
        throw new Exception("Undefined Furniture");
    }
}
Hemendr
źródło
0

Aby odpowiedzieć bezpośrednio na Twoje pytanie, prawdopodobnie możesz uciec bez korzystania z takiego wzorca projektowego.

Pamiętaj jednak, że większość projektów w świecie rzeczywistym ewoluuje i chcesz zapewnić jakąś rozszerzalność, aby Twój projekt był przyszłościowy.

Z własnego doświadczenia wynika, że ​​w większości przypadków wdrażana jest Fabryka, która w miarę rozwoju projektu zmienia się w bardziej złożone wzorce projektowe, takie jak Fabryka Abstrakcji.

BlueTrin
źródło
0

Chodzi o zależności. Jeśli nie zależy Ci na ścisłym sprzężeniu i zależnościach, nie potrzebujesz abstrakcyjnej fabryki. Ale będzie to miało znaczenie, gdy tylko napiszesz aplikację wymagającą konserwacji.

Daniel
źródło
0

Powiedzmy, że tworzysz plik a.jar, a ktoś inny używa twojego jar i chce użyć nowego konkretnego obiektu w twoim kodzie. Jeśli nie używasz fabryki abstrakcji, ona musi zmodyfikować Twój kod lub nadpisać go. Ale jeśli używasz fabryki abstrakcyjnej, ona może dostarczyć fabrykę i przejść do twojego kodu i wszystko jest w porządku.

Udoskonalona wersja: rozważ poniższy scenariusz : Ktoś inny napisał framework. Framework wykorzystuje fabrykę abstrakcyjną i kilka fabryk konkretnych do tworzenia wielu obiektów w czasie wykonywania. Dzięki temu możesz łatwo zarejestrować własną fabrykę w istniejącej strukturze i tworzyć własne obiekty. Struktura jest zamknięta na modyfikacje i nadal łatwa do rozszerzenia ze względu na abstrakcyjny wzór fabryki.

Adrian Liu
źródło
0

Ten wzorzec jest szczególnie przydatny, gdy klient nie wie dokładnie, jaki typ ma utworzyć. Na przykład, powiedzmy, że salon wystawowy sprzedający wyłącznie telefony komórkowe otrzymuje zapytanie dotyczące smartfonów firmy Samsung. Tutaj nie znamy dokładnego typu obiektu, który ma zostać utworzony (zakładając, że wszystkie informacje dla telefonu są opakowane w postać konkretnego obiektu). Ale wiemy, że szukamy smartfonów wyprodukowanych przez firmę Samsung. Te informacje mogą być faktycznie wykorzystane, jeśli nasz projekt ma fabryczną implementację abstrakcyjną.

Zrozumienie i implementacja wzorca fabryki abstrakcyjnej w języku C #

Amir Shabani
źródło