stringtranslate.com

Patrón de método de fábrica

En la programación orientada a objetos , el patrón de método de fábrica es un patrón de diseño que utiliza métodos de fábrica para tratar el problema de crear objetos sin tener que especificar sus clases exactas . En lugar de llamar a un constructor , esto se logra invocando un método de fábrica para crear un objeto. Los métodos de fábrica se pueden especificar en una interfaz e implementar mediante subclases o implementar en una clase base y, opcionalmente, anular mediante subclases. Es uno de los 23 patrones de diseño clásicos descritos en el libro Design Patterns (a menudo denominado "Gang of Four" o simplemente "GoF") y se subcategoriza como un patrón de creación . [1]

Descripción general

El patrón de diseño del método de fábrica resuelve problemas como:

Esto permite la creación de subclases que pueden cambiar la forma en que se crea un objeto (por ejemplo, redefiniendo qué clase instanciar).

Definición

Según Design Patterns: Elements of Reutilizable Object-Oriented Software : "Defina una interfaz para crear un objeto, pero permita que las subclases decidan qué clase instanciar. El método Factory permite que una clase posponga la instanciación que utiliza a las subclases". [2]

La creación de un objeto a menudo requiere procesos complejos que no son apropiados para incluirlos dentro de un objeto que lo compone. La creación del objeto puede llevar a una duplicación significativa de código, puede requerir información inaccesible para el objeto que lo compone, puede no proporcionar un nivel suficiente de abstracción o puede no estar incluida en las preocupaciones del objeto que lo compone . El patrón de diseño del método de fábrica maneja estos problemas definiendo un método separado para crear los objetos, que las subclases pueden anular para especificar el tipo derivado de producto que se creará.

El patrón del método de fábrica se basa en la herencia, ya que la creación de objetos se delega a subclases que implementan el método de fábrica para crear objetos. [3] El patrón también puede basarse en la implementación de una interfaz .

Estructura

Diagrama de clases UML

Un diagrama de clases UML de muestra para el patrón de diseño Método de fábrica. [4]

En el diagrama de clases UML anterior , la clase que requiere un objeto no crea una instancia de la clase directamente. En cambio, hace referencia a un objeto separado para crear un objeto de producto, lo que hace que sea independiente de la clase concreta exacta que se instancia. Las subclases de pueden redefinir qué clase instanciar. En este ejemplo, la subclase implementa lo abstracto al crear una instancia de la clase.CreatorProductProduct1CreatorfactoryMethod()CreatorCreatorCreator1factoryMethod()Product1

Ejemplos

Esta implementación de C++14 se basa en la implementación anterior a C++98 del libro. [5] [ ¿cuál? ]

#include <iostream> #include <memoria>  enum ProductId { MIO , TUYO };   // define la interfaz de los objetos que crea el método de fábrica. class Producto { public : virtual void print () = 0 ; virtual ~ Producto () = default ; };           // implementa la interfaz Producto. clase ConcreteProductMINE : public Product { public : void print () { std :: cout << "this=" << this << " print MINE \n " ; } };               // implementa la interfaz Producto. clase ConcreteProductYOURS : public Product { public : void print () { std :: cout << "this=" << this << " print YOURS \n " ; } };               // declara el método de fábrica, que devuelve un objeto de tipo Producto. class Creator { public : virtual std :: unique_ptr < Product > create ( ProductId id ) { if ( ProductId :: MINE == id ) return std :: make_unique < ConcreteProductMINE > (); if ( ProductId :: YOURS == id ) return std :: make_unique < ConcreteProductYOURS > (); // repetir para los productos restantes...                     devolver nullptr ; } virtual ~ Creador () = predeterminado ; };      int main () { // unique_ptr evita fugas de memoria. std :: unique_ptr < Creador > creador = std :: make_unique < Creador > (); std :: unique_ptr < Producto > producto = creador -> crear ( ProductId :: MINE ); producto -> imprimir ();             producto = creador -> crear ( ProductId :: TUYO ); producto -> imprimir (); }   

La salida del programa es como

esto = 0x6e5e90 imprimir MIO esto = 0x6e62c0 imprimir TUYO    

Un juego de laberinto se puede jugar en dos modos: uno con salas regulares que solo están conectadas con salas adyacentes y otro con salas mágicas que permiten a los jugadores transportarse al azar.

Estructura

Roomes la clase base para un producto final ( MagicRoomo OrdinaryRoom). MazeGamedeclara el método de fábrica abstracto para producir dicho producto base. MagicRoomy OrdinaryRoomson subclases del producto base que implementa el producto final. MagicMazeGamey OrdinaryMazeGameson subclases de MazeGameimplementación del método de fábrica que produce los productos finales. Los métodos de fábrica desacoplan así los llamadores ( MazeGame) de la implementación de las clases concretas. Esto hace que el newoperador sea redundante, permite la adhesión al principio abierto-cerrado y hace que el producto final sea más flexible en caso de cambio.

Ejemplos de implementación

DO#

// Vocabulario vacío del objeto actual interfaz pública IPerson { string GetName (); }    clase pública Aldeano : IPerson { cadena pública GetName () { devolver "Persona del pueblo" ; } }           clase pública CityPerson : IPerson { cadena pública GetName () { return "Persona de la ciudad" ; } }           enumeración pública PersonType { Rural , Urban }    /// <summary> /// Implementación de Factory - Se utiliza para crear objetos. /// </summary> public class PersonFactory { public IPerson GetPerson ( PersonType type ) { switch ( type ) { case PersonType.Rural : return new Villager (); case PersonType.Urban : return new CityPerson ( ); default : throw new NotSupportedException ( ) ; } } }                          

El código anterior muestra la creación de una interfaz llamada IPersony dos implementaciones llamadas Villagery CityPerson. Según el tipo que se pasa al PersonFactoryobjeto, el objeto concreto original se devuelve como la interfaz IPerson.

Un método de fábrica es simplemente un añadido a la PersonFactoryclase. Crea el objeto de la clase a través de interfaces, pero también permite que la subclase decida qué clase se instancia.

interfaz pública IProduct { cadena GetName (); bool SetPrice ( doble precio ); }       clase pública Teléfono : IProducto { privada doble _precio ;        cadena pública GetName () { devolver "Apple TouchPad" ; }       público bool SetPrice ( double precio ) { _price = precio ; devuelve verdadero ; } }          /* Casi igual que Factory, solo una exposición adicional para hacer algo con el método creado */ public abstract class ProductAbstractFactory { protected abstract IProduct MakeProduct ();        public IProduct GetObject () // Implementación del método Factory. { return this.MakeProduct (); } }       clase pública PhoneConcreteFactory : ProductAbstractFactory { protegida anulación IProduct MakeProduct () { IProduct producto = nuevo Phone (); // Hacer algo con el objeto después de recibirlo producto . SetPrice ( 20.30 ); devolver producto ; } }                   

En este ejemplo, MakeProductse utiliza en concreteFactory. Como resultado, MakeProduct()se puede invocar para recuperarlo de IProduct. La lógica personalizada se puede ejecutar después de que se obtenga el objeto en el método de fábrica concreto. GetObjectse vuelve abstracto en la interfaz de fábrica.

Java

Este ejemplo de Java es similar a uno del libro Patrones de diseño .

El MazeGamemétodo de usos Roomdelega la responsabilidad de crear Roomobjetos a sus subclases, que crean las clases concretas. El modo de juego normal podría utilizar este método de plantilla:

clase pública abstracta Habitación { void abstracto connect ( Habitación habitación ); }        clase pública MagicRoom extiende Room { public void connect ( Room room ) {} }          clase pública OrdinaryRoom extiende Room { public void connect ( Room room ) {} }          clase abstracta pública MazeGame { lista final privada < Habitación > habitaciones = nueva ArrayList <> ();            public MazeGame () { Habitación habitación1 = crearHabitación ( ) ; Habitación habitación2 = crearHabitación ( ) ; habitación1.conectar ( habitación2 ) ; habitaciones.añadir ( habitación1 ) ; habitaciones.añadir ( habitación2 ) ; }               abstracto protegido Habitación makeRoom (); }   

El MazeGameconstructor es un método de plantilla que agrega cierta lógica común. Hace referencia al método de fábrica que encapsula la creación de salas de modo que se puedan usar otras salas en una subclase. Para implementar el otro modo de juego que tiene salas mágicas, se puede anular makeRoom()el método:makeRoom

clase pública MagicMazeGame extiende MazeGame { @Override protected MagicRoom makeRoom () { return new MagicRoom (); } }              clase pública OrdinaryMazeGame extiende MazeGame { @Override protected OrdinaryRoom makeRoom () { return new OrdinaryRoom (); } }              JuegoLaberintoJuegoOrdinario = new JuegoLaberintoOrdinario (); JuegoLaberintoJuegoMágico = new JuegoLaberintoMágico ( ) ;        

PHP

Este ejemplo de PHP muestra implementaciones de interfaz en lugar de subclasificación (sin embargo, se puede lograr lo mismo mediante subclasificación). El método de fábrica también se puede definir publicy llamar directamente desde el código del cliente (a diferencia del ejemplo de Java anterior).

/* Interfaces de fábrica y de automóvil */interfaz  CarFactory {  función pública  makeCar () : Car ; }  interfaz  Coche {  función pública  getType () : cadena ; }  /*Implementaciones concretas de la fábrica y del automóvil*/la clase  SedanFactory  implementa  CarFactory {  función pública  makeCar () : Car { devuelve nuevo Sedan (); } }       La clase  Sedan  implementa  Car {  función pública  getType () : string { return 'Sedan' ; } }      /* Cliente */$fábrica  =  new  SedanFactory (); $coche  =  $fábrica -> makeCar (); print  $coche -> getType ();

Pitón

Este ejemplo de Python emplea lo mismo que el ejemplo de Java anterior.

de  abc  importa  ABC ,  método abstractoclase  MazeGame ( ABC ):  def  __init __ ( self )  - >  None :  self.salas = [ ] self._prepare_salas ( )    def  _preparar_salas ( self )  -  > Ninguno :  sala1  =  self.hacer_sala ( ) sala2 = self.hacer_sala ( )    habitación1 . connect ( habitación2 )  self . rooms . append ( habitación1 )  self . rooms . append ( habitación2 ) def  play ( self )  ->  None : print  ( f " Jugando usando { self.rooms [ 0 ] } " ) @abstractmethod  def  make_room ( self ):  raise  NotImplementedError ( "¡Deberías implementar esto!" )clase  MagicMazeGame ( MazeGame ):  def  make_room ( self )  ->  "MagicRoom" :  return  MagicRoom ()clase  OrdinaryMazeGame ( MazeGame ):  def  make_room ( self )  ->  "OrdinaryRoom" :  return  OrdinaryRoom ()clase  Habitación ( ABC ) :  def  __init__ ( self )  ->  None :  self.connected_rooms = [ ]   def  connect ( self ,  room :  " Room " )  - >  None :  self.connected_rooms.append ( room )clase  MagicRoom ( Room ):  def  __str__ ( self )  ->  str :  return  "Sala mágica"clase  HabitacionOrdinaria ( Habitación ):  def  __str__ ( self )  ->  str :  return  "Habitación ordinaria"juegoOrdinario  =  juegoLaberintoOrdinario ( ) juegoOrdinario.play ( )magicGame  =  MagicMazeGame () magicGame . play ()

Usos

Véase también

Notas

  1. ^ Gamma y otros. 1994, pág. 107.
  2. ^ Gamma, Erich ; Helm, Richard ; Johnson, Ralph ; Vlissides, John (1994). Patrones de diseño: elementos de software orientado a objetos reutilizable . Addison-Wesley. ISBN 0-201-63361-2.
  3. ^ Freeman, Eric; Freeman, Elisabeth; Kathy, Sierra; Bert, Bates (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 .
  4. ^ "El patrón de diseño Factory Method - Estructura y colaboración". w3sDesign.com . Consultado el 12 de agosto de 2017 .
  5. ^ Gamma y otros. 1994, pág. 122.

Referencias

Enlaces externos