¿Por qué necesitamos un patrón de diseño abstracto de fábrica?

124

La mayor parte de la definición dice:

Una fábrica abstracta proporciona una interfaz para crear familias de objetos relacionados sin especificar sus clases concretas

¿Cuál es el uso de Abstract Factory Pattern ya que podemos lograr la tarea mediante la creación de objetos de la clase concreta en sí misma? ¿Por qué tenemos un método de fábrica que crea objetos de la clase Concrete?

¿Podría proporcionarme algún ejemplo de la vida real en el que deba implementar el patrón abstractFactory?

Amit
fuente

Respuestas:

219

Abstract Factory es un patrón de diseño muy central para la inyección de dependencia (DI). Aquí hay una lista de preguntas de desbordamiento de pila donde la aplicación de Abstract Factory ha sido aceptada como la solución.

Según tengo entendido, estas preguntas representan preocupaciones o problemas reales que la gente tenía, por lo que debería comenzar con algunos ejemplos de la vida real:

Mark Seemann
fuente
66
Todos estos ejemplos describen el patrón de método de fábrica, porque todos devuelven una única interfaz de producto. Ninguno de estos es un patrón abstracto de fábrica, porque ninguno de ellos produce una familia de interfaces de productos relacionados.
jaco0646
32
En aras de la divulgación completa, el autor de esta respuesta debería haber dejado en claro que él también es el autor de cada una de las respuestas vinculadas; entonces esta lista NO es una muestra representativa de la comunidad SO.
jaco0646
1
@ jaco0646 IIRC, el patrón Método de fábrica es una especialización del patrón Método de plantilla , que se basa en la herencia. Sin embargo, puedo estar equivocado, ya que actualmente estoy viajando, y no tengo mi libro GoF conmigo. ¿Qué quiere decir con "ninguno de ellos produce una familia de interfaces de productos relacionados"?
Mark Seemann
1
La pista más simple que indica que una fábrica no se ajusta al Patrón abstracto de fábrica es contar los productos abstractos que produce la fábrica (utilicé el término "interfaces de producto" en lugar de "productos abstractos" para evitar el uso excesivo de la palabra "resumen") . Una fábrica que produce un solo producto abstracto no puede ser una Fábrica abstracta, porque, por definición, Abstract Factory produce una familia de productos relacionados . Es fundamental tener en cuenta que esta familia no se refiere a diferentes implementaciones de una interfaz, sino a productos con diferentes interfaces relacionadas.
jaco0646
1
Aquí hay un ejemplo oodesign.com/abstract-factory-pattern.html . Para esto se creó originalmente el patrón abstracto de fábrica.
user2802557
23

Un ejemplo de la vida real para el uso del patrón Abstract Factory es proporcionar acceso a datos a dos fuentes de datos diferentes. Suponga que su aplicación admite diferentes almacenes de datos. (por ejemplo, una base de datos SQL y un archivo XML). Tiene dos interfaces de acceso a datos diferentes, por ejemplo, IReadableStorey IWritableStoredefine los métodos comunes que espera su aplicación, independientemente del tipo de fuente de datos utilizada.

El tipo de fuente de datos que se utilizará no debería cambiar la forma en que el código del cliente recupera sus clases de acceso a datos. Tu AbstractDataAccessFactorysabe qué tipo de fuente de datos se configura y se proporciona un hormigón de fábrica para el código de cliente, es decir, SqlDataAccessFactoryo XmlDataAccessFactory. Estas fábricas concretas pueden crear implementaciones concretas, por ejemplo, SqlReadableStorey SqlWriteableStore.

El DbProviderFactory en .NET Framework es un ejemplo de este patrón.

Johannes Rudolph
fuente
18
Esta respuesta podría describir con precisión el patrón del Método de Fábrica, o el patrón de Fábrica Estática, pero no el patrón de Fábrica Abstracta.
jaco0646
5

Si te entiendo bien, la pregunta es, ¿por qué tenemos tanto el método Factory como los patrones abstractos de fábrica? Necesita fábrica abstracta cuando diferentes clases polimórficas tienen un procedimiento de instanciación diferente. Y desea que algún módulo cree instancias y las use, sin conocer ningún detalle de la inicialización de objetos. Por ejemplo, desea crear objetos Java haciendo algunos cálculos. Pero algunos de ellos son parte de la aplicación, mientras que el bytecode de otros debe leerse desde el DB. Por otro lado, ¿por qué necesitamos el método de fábrica? De acuerdo, esa fábrica abstracta se superpone. Pero en algunos casos, es mucho menos código para escribir, tener menos clases e interfaces hace que el sistema sea más fácil de comprender.

David Gruzman
fuente
3

¿Cuál es el uso de Abstract Factory Pattern ya que podemos lograr la tarea mediante la creación de objetos de la clase concreta en sí misma? ¿Por qué tenemos un método de fábrica que crea objetos de la clase Concrete?

En ausencia de Abstract Factory , el Cliente necesita conocer detalles de clases concretas. Este acoplamiento apretado se ha eliminado con Abstract Factory .

Ahora Factory Method expone un contrato que ese cliente debe usar. Puede agregar más productos a su fábrica agregando nuevos productos, que implementan la interfaz expuesta por el Método de fábrica.

Consulte estas preguntas SE relacionadas para una mejor comprensión:

¿Cuál es la diferencia básica entre los patrones Factory y Abstract Factory?

Intención:

Proporcione una interfaz para crear familias de objetos relacionados o dependientes sin especificar sus clases concretas.

Se puede entender Intención, Estructura, Lista de verificación y reglas generales de Abstract Factory patrón de esta sourcemaking artículo.

Lista de Verificación:

  1. Decida si la independencia de la plataforma y los servicios de creación son la fuente actual de dolor.
  2. Mapear una matriz de plataformas versus productos .
  3. Defina una interfaz de fábrica que consista en un método de fábrica por producto.
  4. Defina una clase derivada de fábrica para cada plataforma que encapsule todas las referencias al nuevo operador.
  5. El cliente debe retirar todas las referencias a nuevas y utilizar los métodos de fábrica para crear los objetos del producto .
Ravindra babu
fuente
2

Las Fábricas abstractas son excelentes para soportar múltiples plataformas mientras mantienen unida su base de código. Suponga que tiene un gran programa Qt o GTK + o .NET / Mono que desea ejecutar en Windows, Linux y OSX. Pero tiene una función que se implementa de manera diferente en cada plataforma (quizás a través de la API kernel32 o una función 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
}

Con esta Fábrica abstracta, su IU no necesita saber nada sobre la plataforma actual.

Feature feature = Feature.PlatformFeature;
Console.WriteLine(feature.PlatformSpecificValue);
piedar
fuente
1
No lo entiendo, ¿cómo es esto diferente de simplemente usar métodos de fábrica para devolver un tipo abstracto para que el cliente no conozca los detalles de implementación?
kiwicomb123
1

Si observa los patrones de diseño, casi todos se pueden hacer redundantes. Pero, ¿qué patrón significa un enfoque comúnmente utilizado para una solución a un tipo similar de problemas? Un patrón de diseño le proporciona un enfoque o solución a nivel de diseño para un conjunto de problemas de diseño de tipo similar. El uso del patrón de diseño lo ayuda a resolver su problema y, por lo tanto, a entregar más rápido.

Kangkan
fuente
1

Es fácil, imaginando que tiene un código que funciona con la abstracción, debe crear abstracciones y no clases concretas.

Siempre debe trabajar contra las abstracciones porque puede modificar el código mejor.

Este es un buen ejemplo: http://en.wikipedia.org/wiki/Abstract_factory_pattern#C.23

Pablo Castilla
fuente
1

Encuentro el patrón Abstract Factory sobrevalorado.

En primer lugar, no sucede tan a menudo que tenga un conjunto de tipos interrelacionados que desea instanciar.

En segundo lugar, el nivel de indirección (abstracción) proporcionado por las interfaces normalmente es suficiente cuando se trabaja con inyección de dependencia.

El ejemplo típico de WindowsGui vs MacGui vs ... donde tendrías un WindowsButton, MacButton, WindowsScrollBar, MacScrollbar, etc. es a menudo más fácil de implementar definiendo botones, barras de desplazamiento, etc. concretos usando el patrón Visitor y / o Intérprete para proporcionar comportamiento real

eljenso
fuente
Hay un propósito específico para ello. con la inyección de dependencia no desea ubicadores de servicio más abajo de la raíz compuesta. en su lugar, usa una fábrica abstracta inyectada.
Adam Tuliper - MSFT
2
bueno ... usar el localizador de servicios con DI es un anti patteren. An Abstract Factory es la solución universal cuando necesitamos crear DEPENDENCIAS a partir de valores de tiempo de ejecución.
TheMentor
1

Creo que hay un lugar para el patrón de fábrica abstracto en lugar del patrón de fábrica simple en lugares donde sus instancias son muy complicadas, demasiado complicadas y feas para una sola fábrica y demasiado complicadas para que la UI las comprenda.

Digamos que esta es una marca TYPE_A, no una sola clase. Digamos que hay una familia de 100 clases similares de Tipo-A y necesita crear una instancia de un objeto de ellas. Imagine que se necesita una información sofisticada detallada para hacer el objeto correcto de una marca de muchos tipos de objetos similares, y en esta entidad de objeto necesita saber exactamente qué parámetros ajustar y cómo ajustarlos.

En la fábrica especial para esta marca, haremos que se diferencien y obtengan el objeto exacto para instanciar y también cómo hacerlo. sabremos eso de acuerdo con la información de la red (digamos de qué color está disponible en la tienda en línea), y de otras aplicaciones y servicios que se ejecutan en segundo plano (parámetros que la UI no conoce).

Y tal vez mañana tendremos otra familia de digamos type_B y type_C para instanciar. Por lo tanto, la interfaz de usuario tendrá el "if else" para saber si el usuario quiere un "type_A", "type_B" o "type_C", pero las clases de fábricas decidirán exactamente qué clase del tipo (de la familia) construir, y cómo ajustarlo: qué valores establecer en sus parámetros o enviar a su contratista. Todo esto, de acuerdo con muchos parámetros que la interfaz de usuario no conoce. Todo esto será demasiado para una sola clase de fábrica.

Udi Reshef
fuente
0

Para responder directamente a su pregunta, probablemente pueda escapar sin usar un patrón de diseño de este tipo.

Sin embargo, tenga en cuenta que la mayoría de los proyectos en el mundo real evolucionan y desea proporcionar algún tipo de extensibilidad para que su proyecto esté preparado para el futuro.

Desde mi propia experiencia, la mayoría de las veces, se implementa una Fábrica y, a medida que el proyecto crece, cambia a patrones de diseño más complejos, como una Fábrica abstracta.

BlueTrin
fuente
0

Se trata de dependencias. Si no le importa el acoplamiento estrecho y las dependencias, entonces no necesita una fábrica abstracta. Pero importará tan pronto como escriba una aplicación que necesite mantenimiento.

Daniel
fuente
0

Supongamos que crea a.jar, y alguien más usa su jar y quiere usar un nuevo objeto concreto en su código. Si no está utilizando la fábrica abstracta, entonces ella tiene que modificar su código o sobrescribirlo. Pero si está usando una fábrica abstracta, entonces ella puede proporcionar una fábrica y pasar su código y todo está bien.

Versión refinada: considere el siguiente escenario: alguien más escribió un marco. El marco utiliza una fábrica abstracta y algunas fábricas concretas para crear muchos objetos en tiempo de ejecución. Por lo tanto, puede registrar fácilmente su propia fábrica en el marco existente y crear sus propios objetos. El marco está cerrado a modificaciones y aún es fácil de extender debido al patrón abstracto de fábrica.

Adrian Liu
fuente
0

Este patrón es particularmente útil cuando el cliente no sabe exactamente qué tipo crear. Como ejemplo, supongamos que un Showroom que vende teléfonos celulares exclusivamente recibe una consulta para los teléfonos inteligentes fabricados por Samsung. Aquí no sabemos el tipo exacto de objeto que se creará (suponiendo que toda la información para un teléfono esté envuelta en forma de un objeto concreto). Pero sí sabemos que estamos buscando teléfonos inteligentes fabricados por Samsung. Esta información se puede utilizar si nuestro diseño tiene implementación de fábrica abstracta.

Comprender e implementar el patrón abstracto de fábrica en C #

Amir Shabani
fuente
0

El ejemplo de la vida real se proporciona en el espacio de nombres System.Data.Common que tiene clases base abstractas que incluyen DbConnection, DbCommand y DbDataAdapter y son compartidas por los proveedores de datos de .NET Framework, como System.Data.SqlClient y System.Data.OracleClient que permitir a un desarrollador escribir código genérico de acceso a datos que no dependa de un proveedor de datos específico.

La clase DbProviderFactories proporciona métodos estáticos para crear una instancia de DbProviderFactory. La instancia luego devuelve un objeto correcto fuertemente tipado basado en la información del proveedor y la cadena de conexión suministrada en tiempo de ejecución.

Ejemplo:

 DataTable allProvidersTable = DbProviderFactories.GetFactoryClasses();

ingrese la descripción de la imagen aquí

        /* 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;

Ejemplo 2 ingrese la descripción de la imagen aquí

Arquitectura de solución de código ingrese la descripción de la imagen aquí

Se proporcionan instancias de fábrica de concreto utilizando el método de fábrica estático como se muestra a continuación

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
fuente