stringtranslate.com

Patrón de fábrica abstracto

Diagrama de clases UML

El patrón de fábrica abstracta en ingeniería de software es un patrón de diseño que proporciona una forma de crear familias de objetos relacionados sin imponer sus clases concretas, encapsulando un grupo de fábricas individuales que tienen un tema común sin especificar sus clases concretas. [1] Según este patrón, un componente de software cliente crea una implementación concreta de la fábrica abstracta y luego utiliza la interfaz genérica de la fábrica para crear los objetos concretos que forman parte de la familia. El cliente no sabe qué objetos concretos recibe de cada una de estas fábricas internas, ya que utiliza solo las interfaces genéricas de sus productos. [1] Este patrón separa 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 la fábrica. [2]

El uso de este patrón permite implementar implementaciones concretas intercambiables sin cambiar el código que las utiliza, incluso en tiempo de ejecución . Sin embargo, el uso de este patrón, al igual que con patrones de diseño similares , puede generar una complejidad innecesaria y trabajo extra en la escritura inicial del código. Además, niveles más altos de separación y abstracción pueden generar sistemas que sean más difíciles de depurar y mantener.

Descripción general

El patrón de diseño de fábrica abstracta es uno de los 23 patrones descritos en el libro Design Patterns de 1994. Puede utilizarse para resolver problemas como: [3]

La creación de objetos directamente dentro de la clase que los requiere es inflexible. Al hacerlo, se compromete la clase con objetos particulares y se hace imposible cambiar la instanciación más adelante sin cambiar la clase. Esto impide 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.

Una fábrica es la ubicación de una clase concreta en el código en la que se construyen los objetos . La implementación del patrón pretende aislar la creación de objetos de su uso y crear familias de objetos relacionados sin depender de sus clases concretas. [2] Esto permite introducir nuevos tipos derivados sin cambiar el código que utiliza la clase base .

El patrón describe cómo resolver tales problemas:

Esto hace que una clase sea independiente de cómo se crean sus objetos. Una clase puede configurarse con un objeto de fábrica, que utiliza para crear objetos, y el objeto de fábrica puede intercambiarse en tiempo de ejecución.

Definición

Design Patterns describe el patrón de fábrica abstracto como "una interfaz para crear familias de objetos relacionados o dependientes sin especificar sus clases concretas". [4]

Uso

La fábrica determina el tipo concreto del objeto que se va a crear y es aquí donde se crea realmente el objeto. Sin embargo, la fábrica solo devuelve una referencia (en Java, por ejemplo, mediante el operador new ) o un puntero de un tipo abstracto al objeto concreto creado.

Esto aísla el código del cliente de la creación de objetos al hacer que los clientes soliciten que un objeto de fábrica cree un objeto del tipo abstracto deseado y devuelva un puntero abstracto al objeto. [5]

Un ejemplo es una clase de fábrica abstracta DocumentCreatorque 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 DocumentCreatorclase, como FancyDocumentCreatoro ModernDocumentCreator, cada una con una implementación diferente de createLetter()y createResume()que crearía objetos correspondientes, como FancyLettero ModernResume. Cada uno de estos productos se deriva de una clase abstracta simple , como Lettero , Resumede la que el cliente es consciente. El código del cliente adquiriría una instancia apropiada de DocumentCreatory llamaría a sus métodos de fábrica . Cada uno de los objetos resultantes se crearía a partir de la misma DocumentCreatorimplementación y compartiría un tema común. El cliente solo necesitaría saber cómo manejar la clase abstracta Lettero Resume, no la versión específica que fue creada por la fábrica concreta.

Como la fábrica solo devuelve una referencia o un puntero a un tipo abstracto, el código del cliente que solicitó el objeto a la fábrica no conoce (y no se ve afectado por) el tipo concreto real del objeto que se creó. Sin embargo, la fábrica abstracta conoce el tipo de un objeto concreto (y, por lo tanto, una fábrica concreta). Por ejemplo, la fábrica puede leer el tipo del objeto desde un archivo de configuración. El cliente no tiene necesidad de especificar el tipo, ya que este ya se ha especificado en el archivo de configuración. En particular, esto significa:

Estructura

Diagrama UML

Un ejemplo de diagrama de clase y secuencia UML para el patrón de diseño de fábrica abstracta. [7]

En el diagrama de clases UML anterior , la clase que requiere objetos y no instancia las clases y directamente. En cambio, hace referencia a la interfaz para crear objetos, lo que hace que la interfaz sea independiente de cómo se crean los objetos (qué clases concretas se instancian). La clase implementa la interfaz instanciando las clases y .ClientProductAProductBProductA1ProductB1ClientAbstractFactoryClientFactory1AbstractFactoryProductA1ProductB1

El diagrama de secuencia UML muestra las interacciones en tiempo de ejecución. El objeto llama al objeto, que crea y devuelve un objeto. A continuación, llama a , que crea y devuelve un objeto.ClientcreateProductA()Factory1ProductA1ClientcreateProductB()Factory1ProductB1

Variantes

La estructura original del patrón de fábrica abstracta, tal como se definió en 1994 en Design Patterns , se basa en clases abstractas para la fábrica abstracta y los productos abstractos que se crearán. Las fábricas y los productos concretos son clases que especializan las clases abstractas mediante herencia. [4]

Una estructura más reciente del patrón se basa en interfaces que definen la fábrica abstracta y los productos abstractos que se van a crear. Este diseño utiliza soporte nativo para interfaces o protocolos en los lenguajes de programación más utilizados para evitar la herencia. En este caso, las fábricas y los productos concretos son clases que materializan la interfaz al implementarla. [1]

Ejemplo

Esta implementación de C++11 se basa en la implementación anterior a C++98 del libro.

#include <flujo de datos> enumeración Dirección { Norte , Sur , Este , Oeste };     clase MapSite { público : virtual void enter () = 0 ; virtual ~ MapSite () = predeterminado ; };           clase Habitación : público MapSite { público : Habitación () : númeroDeHabitación ( 0 ) {} Habitación ( int n ) : númeroDeHabitación ( n ) {} void setSide ( Dirección d , MapSite * ms ) { std :: cout << "Habitación::setSide " << d << ' ' << ms << '\n' ; } virtual void enter () {} Habitación ( const Habitación & ) = delete ; // regla de tres Habitación & operador = ( const Habitación & ) = delete ; privado : int númeroDeHabitación ; };                                              clase Muro : público MapSite { público : Muro () {} virtual void enter () {} };           clase Puerta : público MapSite { público : Puerta ( Habitación * r1 = nullptr , Habitación * r2 = nullptr ) : habitación1 ( r1 ), habitación2 ( r2 ) {} virtual void enter () {} Puerta ( const Puerta & ) = eliminar ; // regla de tres Puerta & operador = ( const Puerta & ) = eliminar ; privado : Habitación * habitación1 ; Habitación * habitación2 ; };                                  clase Laberinto { público : void addRoom ( Habitación * r ) { std :: cout << "Laberinto::addRoom " << r << '\n' ; } Habitación * roomNo ( int ) const { return nullptr ; } };                     clase MazeFactory { público : MazeFactory () = predeterminado ; virtual ~ MazeFactory () = predeterminado ;          Laberinto virtual * makeMaze () const { devuelve nuevo Laberinto ; } Muro virtual * makeWall () const { devuelve nuevo Muro ; } Habitación virtual * makeRoom ( int n ) const { devuelve nueva Habitación ( n ); } Puerta virtual * makeDoor ( Habitación * r1 , Habitación * r2 ) const { devuelve nueva Puerta ( r1 , r2 ); } };                                        // Si se pasa un objeto a createMaze como parámetro para crear habitaciones, paredes y puertas, entonces se pueden cambiar las clases de habitaciones, paredes y puertas pasando un parámetro diferente. Este es un ejemplo del patrón Abstract Factory (99).clase MazeGame { public : Maze * createMaze ( MazeFactory & factory ) { Laberinto * aMaze = factory . makeMaze (); Habitación * r1 = factory . makeRoom ( 1 ); Habitación * r2 = factory . makeRoom ( 2 ); Puerta * aDoor = factory . makeDoor ( r1 , r2 ); aMaze -> addRoom ( r1 ); aMaze -> addRoom ( r2 ); r1 -> setSide ( Norte , factory . makeWall ()); r1 -> setSide ( Este , aDoor ); r1 -> setSide ( Sur , factory . makeWall ()); r1 -> setSide ( Oeste , factory . makeWall ()); r2 -> setSide ( Norte , factory . makeWall ()); r2 -> setSide ( Este , factory . makeWall ()); r2 -> setSide ( Sur , fábrica . makeWall ()); r2 -> setSide ( Oeste , una Puerta ); devolver un laberinto ; } };                                            int main ( ) { MazeGame juego ; MazeFactory fábrica ; juego.createMaze ( fábrica ) ; }       

La salida del programa es:

Laberinto::addRoom 0x1317ed0 Laberinto::addRoom 0x1317ef0 Habitación::setSide 0 0x1318340 Habitación::setSide 2 0x1317f10 Habitación::setSide 1 0x1318360 Habitación::setSide 3 0x1318380 Habitación::setSide 0x13183a 0 Habitación::setSide 2 0x13183c0 Habitación::setSide 1 0x13183e0 Habitación::setLado 3 0x1317f10

Véase también

Referencias

  1. ^ abc Freeman, Eric; Robson, Elisabeth; Sierra, Kathy; Bates, Bert (2004). Hendrickson, Mike; Loukides, Mike (eds.). Patrones de diseño Head First (libro de bolsillo) . Vol. 1. O'REILLY. pág. 156. ISBN 978-0-596-00712-6. Recuperado el 12 de septiembre de 2012 .
  2. ^ ab Freeman, Eric; Robson, Elisabeth; Sierra, Kathy; Bates, Bert (2004). Hendrickson, Mike; Loukides, Mike (eds.). Patrones de diseño Head First (libro de bolsillo) . Vol. 1. O'REILLY. pág. 162. ISBN 978-0-596-00712-6. Recuperado el 12 de septiembre de 2012 .
  3. ^ "El patrón de diseño Abstract Factory: problema, solución y aplicabilidad". w3sDesign.com . Consultado el 11 de agosto de 2017 .
  4. ^ ab Gamma, Erich; Richard Helm; Ralph Johnson; John M. Vlissides (23 de octubre de 2009). "Patrones de diseño: Abstract Factory". informIT. Archivado desde el original el 16 de mayo de 2012. Consultado el 16 de mayo de 2012. Creación de objetos: Abstract Factory: Propósito: Proporcionar una interfaz para crear familias de objetos relacionados o dependientes sin especificar sus clases concretas.{{cite web}}: CS1 maint: bot: estado de URL original desconocido ( enlace )
  5. ^ Veeneman, David (23 de octubre de 2009). "Diseño de objetos para los perplejos". The Code Project. Archivado desde el original el 21 de febrero de 2011. Consultado el 16 de mayo de 2012. La fábrica aísla al cliente de los cambios en el producto o en la forma en que se crea, y puede proporcionar este aislamiento en objetos derivados de interfaces abstractas muy diferentes.{{cite web}}: CS1 maint: bot: estado de URL original desconocido ( enlace )
  6. ^ ab "Abstract Factory: Implementation". OODesign.com . Consultado el 16 de mayo de 2012 .
  7. ^ "El patrón de diseño Abstract Factory: estructura y colaboración". w3sDesign.com . Consultado el 12 de agosto de 2017 .

Enlaces externos