El patrón de fábrica abstracto proporciona una forma de encapsular un grupo de fábricas individuales que tienen un tema común sin especificar sus clases concretas. [1] En uso normal, el software cliente crea una implementación concreta de la fábrica abstracta y luego usa la interfaz genérica de la fábrica para crear los objetos concretos que son parte del tema. El cliente no sabe (ni le importa) qué objetos concretos obtiene de cada una de estas fábricas internas, ya que utiliza únicamente las interfaces genéricas de sus productos. [1] Este patrónsepara los detalles de implementación de un conjunto de objetos de su uso general y se basa en la composición de objetos, ya que la creación de objetos se implementa en métodos expuestos en la interfaz de fábrica. [2]
Un ejemplo de esto sería una clase de fábrica abstracta DocumentCreator
que proporciona interfaces para crear una serie de productos (por ejemplo, createLetter()
y createResume()
). El sistema tendría cualquier número de versiones concretas derivadas de la DocumentCreator
clase como FancyDocumentCreator
o ModernDocumentCreator
, cada una con una implementación diferente de createLetter()
y createResume()
que crearía un objeto correspondiente como FancyLetter
o ModernResume
. Cada uno de estos productos se deriva de una clase abstracta simple como Letter
o Resume
de la que el cliente es consciente. El código del cliente obtendría una instancia apropiada de DocumentCreator
y llamaría a sus métodos de fábrica . Cada uno de los objetos resultantes se crearía a partir de la misma DocumentCreator
implementación y compartiría un tema común (todos serían objetos elegantes o modernos). El cliente solo necesitaría saber cómo manejar el resumen Letter
o la Resume
clase, no la versión específica que obtuvo de la fábrica de concreto.
Una fábrica es la ubicación de una clase concreta en el código en el que se construyen los objetos . La intención al emplear el patrón es aislar la creación de objetos de su uso y crear familias de objetos relacionados sin tener que depender de sus clases concretas. [2] Esto permite introducir nuevos tipos derivados sin cambios en el código que usa la clase base .
El uso de este patrón permite intercambiar implementaciones concretas sin cambiar el código que las usa, incluso en tiempo de ejecución . Sin embargo, el empleo de este patrón, al igual que con patrones de diseño similares , puede resultar en una complejidad innecesaria y trabajo adicional en la escritura inicial del código. Además, los niveles más altos de separación y abstracción pueden resultar en sistemas que son más difíciles de depurar y mantener.
Descripción general
El patrón de diseño Abstract Factory [3] es uno de los veintitrés patrones de diseño GoF bien conocidos que describen cómo resolver problemas de diseño recurrentes para diseñar software orientado a objetos flexible y reutilizable, es decir, objetos que son más fáciles de implementar, cambiar , probar y reutilizar.
El patrón de diseño Abstract Factory resuelve problemas como: [4]
- ¿Cómo puede una aplicación ser independiente de cómo se crean sus objetos?
- ¿Cómo puede una clase ser independiente de cómo se crean los objetos que requiere?
- ¿Cómo se pueden crear familias de objetos relacionados o dependientes?
La creación de objetos directamente dentro de la clase que requiere los objetos es inflexible porque compromete la clase a objetos particulares y hace que sea imposible cambiar la instanciación más adelante independientemente de (sin tener que cambiar) la clase. Evita que la clase sea reutilizable si se requieren otros objetos y dificulta la prueba de la clase porque los objetos reales no se pueden reemplazar con objetos simulados.
El patrón de diseño de Abstract Factory describe cómo resolver tales problemas:
- Encapsular la creación de objetos en un objeto separado (de fábrica). Es decir, defina una interfaz (AbstractFactory) para crear objetos e implemente la interfaz.
- Una clase delega la creación de objetos a un objeto de fábrica en lugar de crear objetos directamente.
Esto hace que una clase sea independiente de cómo se crean sus objetos (qué clases concretas se instancian). Una clase se puede configurar con un objeto de fábrica, que utiliza para crear objetos, y aún más, el objeto de fábrica se puede intercambiar en tiempo de ejecución.
Definición
La esencia del Abstract Factory Pattern es "Proporcionar una interfaz para crear familias de objetos relacionados o dependientes sin especificar sus clases concretas". [5]
Uso
La fábrica determina el tipo concreto real de objeto que se va a crear, y es aquí donde el objeto se crea realmente (en C ++, por ejemplo, por el nuevo operador ). Sin embargo, la fábrica solo devuelve un puntero abstracto al objeto concreto creado .
Esto aísla el código del cliente de la creación de objetos al hacer que los clientes pidan a un objeto de fábrica que cree un objeto del tipo abstracto deseado y que devuelva un puntero abstracto al objeto. [6]
Como la fábrica solo devuelve un puntero abstracto, el código del cliente (que solicitó el objeto de la fábrica) no conoce, y no está agobiado por, el tipo concreto real del objeto que se acaba de crear. Sin embargo, el tipo de objeto concreto (y por lo tanto una fábrica de concreto) es conocido por la fábrica abstracta; por ejemplo, la fábrica puede leerlo desde un archivo de configuración. El cliente no necesita especificar el tipo, ya que ya se ha especificado en el archivo de configuración. En particular, esto significa:
- El código del cliente no tiene conocimiento alguno del tipo concreto , no necesita incluir ningún archivo de encabezado o declaraciones de clase relacionadas con él. El código de cliente trata solo con el tipo abstracto. De hecho, los objetos de un tipo concreto son creados por la fábrica, pero el código del cliente accede a dichos objetos solo a través de su interfaz abstracta . [7]
- La adición de nuevos tipos de concreto se realiza modificando el código del cliente para usar una fábrica diferente, una modificación que suele ser una línea en un archivo. Luego, la fábrica diferente crea objetos de un tipo concreto diferente , pero aún devuelve un puntero del mismo tipo abstracto que antes, aislando así el código del cliente del cambio. Esto es significativamente más fácil que modificar el código del cliente para crear una instancia de un nuevo tipo, lo que requeriría cambiar cada ubicación en el código donde se crea un nuevo objeto (además de asegurarse de que todas esas ubicaciones de código también tengan conocimiento del nuevo tipo concreto, incluyendo, por ejemplo, un archivo de encabezado de clase concreto). Si todos los objetos de fábrica se almacenan globalmente en un objeto singleton , y todo el código del cliente pasa por el singleton para acceder a la fábrica adecuada para la creación de objetos, entonces cambiar las fábricas es tan fácil como cambiar el objeto singleton. [7]
Estructura
Diagrama UML
En el diagrama de clases de UML anterior , la Client
clase que requiere los objetos ProductA
y ProductB
no crea una instancia de las clases ProductA1
y ProductB1
directamente. En cambio, se Client
refiere a la AbstractFactory
interfaz para crear objetos, lo que hace que sea Client
independiente de cómo se crean los objetos (qué clases concretas se instancian). La Factory1
clase implementa la AbstractFactory
interfaz creando instancias de las clases ProductA1
y ProductB1
.
El diagrama de secuencia UML muestra las interacciones en tiempo de ejecución: El Client
objeto llama createProductA()
al Factory1
objeto, que crea y devuelve un ProductA1
objeto. A partir de entonces, las Client
llamadas createProductB()
a Factory1
, que crean y devuelven un ProductB1
objeto.
Gráfico Lepus3
Ejemplo de Python
de abc import ABC , método abstracto de la plataforma de importación sys Botón de clase ( ABC ): @abstractmethod def paint ( self ): passclass LinuxButton ( Botón ): def paint ( self ): return "Renderizar un botón en un estilo Linux"clase WindowsButton ( Botón ): def paint ( self ): return "Renderizar un botón en un estilo de Windows"class MacOSButton ( Botón ): def paint ( self ): return "Renderizar un botón en un estilo MacOS"class GUIFactory ( ABC ): @abstractmethod def create_button ( self ): passclase LinuxFactory ( GUIFactory ): def create_button ( self ): return LinuxButton ()clase WindowsFactory ( GUIFactory ): def create_button ( self ): return WindowsButton ()clase MacOSFactory ( GUIFactory ): def create_button ( self ): return MacOSButton ()if platform == "linux" : factory = LinuxFactory () elif platform == "darwin" : factory = MacOSFactory () elif platform == "win32" : factory = WindowsFactory () else : raise NotImplementedError ( f "No implementado para su plataforma: { plataforma } " )botón = fábrica . create_button () resultado = botón . pintar () imprimir ( resultado )
Implementación alternativa utilizando las propias clases como fábricas:
de abc import ABC , método abstracto de la plataforma de importación sys Botón de clase ( ABC ): @abstractmethod def paint ( self ): passclass LinuxButton ( Botón ): def paint ( self ): return "Renderizar un botón en un estilo Linux"clase WindowsButton ( Botón ): def paint ( self ): return "Renderizar un botón en un estilo de Windows"class MacOSButton ( Botón ): def paint ( self ): return "Renderizar un botón en un estilo MacOS"if platform == "linux" : factory = LinuxButton elif platform == "darwin" : factory = MacOSButton elif platform == "win32" : factory = WindowsButton else : raise NotImplementedError ( f "No implementado para su plataforma: { plataforma } " )botón = fábrica () resultado = botón . pintar () imprimir ( resultado )
Ver también
- Clase concreta
- Patrón de método de fábrica
- Creación de objetos
- Patrón de diseño de software
Referencias
- ^ a b Freeman, Eric; Robson, Elisabeth; Sierra, Kathy; Bates, Bert (2004). Hendrickson, Mike; Loukides, Mike (eds.). Head First Design Patterns (rústica) . 1 . O'REILLY. pag. 156. ISBN 978-0-596-00712-6. Consultado el 12 de septiembre de 2012 .
- ^ a b Freeman, Eric; Robson, Elisabeth; Sierra, Kathy; Bates, Bert (2004). Hendrickson, Mike; Loukides, Mike (eds.). Head First Design Patterns (rústica) . 1 . O'REILLY. pag. 162. ISBN 978-0-596-00712-6. Consultado el 12 de septiembre de 2012 .
- ^ Erich Gamma; Richard Helm; Ralph Johnson; John Vlissides (1994). Patrones de diseño: elementos de software orientado a objetos reutilizable . Addison Wesley. págs. 87 y siguientes . ISBN 0-201-63361-2.
- ^ "El patrón de diseño de la fábrica abstracta: problema, solución y aplicabilidad" . w3sDesign.com . Consultado el 11 de agosto de 2017 .
- ^ Gamma, Erich; Richard Helm; Ralph Johnson; John M. Vlissides (23 de octubre de 2009). "Patrones de diseño: Fábrica abstracta" . informIT. Archivado desde el original el 23 de octubre de 2009 . Consultado el 16 de mayo de 2012 .
Creación de objetos: Fábrica abstracta: Intención: Proporcionar una interfaz para crear familias de objetos relacionados o dependientes sin especificar sus clases concretas.
- ^ Veeneman, David (23 de octubre de 2009). "Diseño de objetos para los perplejos" . El proyecto de código. Archivado desde el original el 18 de septiembre de 2011 . Consultado el 16 de mayo de 2012 .
La fábrica aísla al cliente de los cambios en el producto o cómo se crea, y puede proporcionar este aislamiento a través de objetos derivados de interfaces abstractas muy diferentes.
- ^ a b "Abstract Factory: Implementación" . OODesign.com . Consultado el 16 de mayo de 2012 .
- ^ "El patrón de diseño de Abstract Factory - Estructura y colaboración" . w3sDesign.com . Consultado el 12 de agosto de 2017 .
enlaces externos
- Implementación de Abstract Factory en Java
- Medios relacionados con la fábrica abstracta en Wikimedia Commons
- Diagrama UML Abstract Factory + especificación formal en LePUS3 y Class-Z (un lenguaje de descripción de diseño)
- Ejemplo de implementación de Abstract Factory Abstract Factory