stringtranslate.com

Fábrica (programación orientada a objetos)

Método de fábrica en LePUS3

En la programación orientada a objetos , una fábrica es un objeto para crear otros objetos ; formalmente, es una función o método que devuelve objetos de un prototipo o clase variable [1] a partir de alguna llamada de método, que se supone que es "nueva". [a] En términos más generales, una subrutina que devuelve un objeto "nuevo" puede denominarse "fábrica", como en método de fábrica o función de fábrica . El patrón de fábrica es la base de varios patrones de diseño de software relacionados .

Motivación

En la programación basada en clases , una fábrica es una abstracción de un constructor de una clase, mientras que en la programación basada en prototipos una fábrica es una abstracción de un objeto prototipo. Un constructor es concreto en el sentido de que crea objetos como instancias de una sola clase y mediante un proceso especificado (instanciación de clase), mientras que una fábrica puede crear objetos instanciando varias clases o utilizando otros esquemas de asignación como un grupo de objetos . Un objeto prototipo es concreto en el sentido de que se utiliza para crear objetos al ser clonado , mientras que una fábrica puede crear objetos clonando varios prototipos o mediante otros esquemas de asignación.

Una fábrica se puede implementar de varias maneras. La mayoría de las veces se implementa como un método, en cuyo caso se denomina método de fábrica . A veces se implementa como una función, en cuyo caso se denomina función de fábrica . En algunos lenguajes, los constructores son en sí mismos fábricas. Sin embargo, en la mayoría de los lenguajes no lo son, y los constructores se invocan de una manera que es idiomática para el lenguaje, como mediante el uso de la palabra clave new, mientras que una fábrica no tiene un estatus especial y se invoca a través de una llamada a un método o una llamada a una función ordinaria. En estos lenguajes, una fábrica es una abstracción de un constructor, pero no estrictamente una generalización, ya que los constructores no son en sí mismos fábricas.

Terminología

La terminología difiere en cuanto a si el concepto de una fábrica es en sí mismo un patrón de diseño: en los patrones de diseño no hay un "patrón de fábrica", sino dos patrones ( patrón de método de fábrica y patrón de fábrica abstracto ) que utilizan fábricas. Algunas fuentes se refieren al concepto como el patrón de fábrica , [2] [3] mientras que otras consideran el concepto en sí un modismo de programación , [4] reservando el término "patrón de fábrica" ​​o "patrones de fábrica" ​​para patrones más complicados que utilizan fábricas, más a menudo el patrón de método de fábrica; en este contexto, el concepto de una fábrica en sí puede denominarse una fábrica simple. [4] En otros contextos, particularmente el lenguaje Python, se utiliza "fábrica" ​​en sí, como en este artículo. [5] De manera más amplia, "fábrica" ​​puede aplicarse no solo a un objeto que devuelve objetos de alguna llamada de método, sino a una subrutina que devuelve objetos, como en una función de fábrica (incluso si las funciones no son objetos) o un método de fábrica. [6] Debido a que en muchos lenguajes las fábricas se invocan llamando a un método, el concepto general de una fábrica a menudo se confunde con el patrón de diseño de método de fábrica específico .

Usar

La programación orientada a objetos proporciona polimorfismo en el uso de objetos mediante el método dispatch , formalmente polimorfismo de subtipos mediante un único dispatch determinado por el tipo de objeto en el que se llama al método. Sin embargo, esto no funciona para los constructores, ya que los constructores crean un objeto de algún tipo, en lugar de utilizar un objeto existente. Más concretamente, cuando se llama a un constructor, todavía no hay ningún objeto en el que enviar. [b]

El uso de fábricas en lugar de constructores o prototipos permite utilizar el polimorfismo para la creación de objetos, no solo para su uso. En concreto, el uso de fábricas proporciona encapsulación y significa que el código no está ligado a clases u objetos específicos, por lo que la jerarquía de clases o los prototipos se pueden cambiar o refactorizar sin necesidad de cambiar el código que los utiliza; se abstraen de la jerarquía de clases o los prototipos.

Más técnicamente, en lenguajes donde las fábricas generalizan constructores, las fábricas pueden usarse usualmente en cualquier lugar donde se puedan usar constructores, [c] lo que significa que las interfaces que aceptan un constructor también pueden, en general, aceptar una fábrica – usualmente uno solo necesita algo que cree un objeto, en lugar de tener que especificar una clase y una instanciación.

Por ejemplo, en Python, la collections.defaultdictclase [7] tiene un constructor que crea un objeto de tipo defaultdict[d] cuyos valores predeterminados se generan invocando una fábrica. La fábrica se pasa como argumento al constructor y puede ser un constructor o cualquier cosa que se comporte como un constructor (un objeto invocable que devuelve un objeto, es decir, una fábrica). Por ejemplo, si se utiliza el listconstructor para listas:

# colecciones.defaultdict([default_factory[, ...]]) d  =  defaultdict ( lista )

Creación de objetos

Los objetos de fábrica se utilizan en situaciones en las que obtener un objeto de un tipo particular es un proceso más complejo que simplemente crear un nuevo objeto, especialmente si se desea una asignación o inicialización compleja. Algunos de los procesos necesarios en la creación de un objeto incluyen determinar qué objeto crear, administrar la vida útil del objeto y administrar las preocupaciones especializadas de creación y desmantelamiento del objeto. El objeto de fábrica puede decidir crear la clase del objeto (si corresponde) de forma dinámica, devolverla desde un grupo de objetos , realizar una configuración compleja en el objeto u otras cosas. De manera similar, utilizando esta definición, un singleton implementado por el patrón singleton es una fábrica formal: devuelve un objeto, pero no crea nuevos objetos más allá de la instancia única.

Ejemplos

El ejemplo más simple de una fábrica es una función de fábrica simple, que simplemente invoca un constructor y devuelve el resultado. En Python, una función de fábrica fque crea una instancia de una clase Ase puede implementar de la siguiente manera:

def  f ():  devuelve  A ()

Una función de fábrica simple que implementa el patrón singleton es:

def  f ( )  : si  f.obj es Ninguno : f.obj = A ( ) devuelve f.obj       f . obj  =  Ninguno

Esto creará un objeto cuando se llame por primera vez y siempre devolverá el mismo objeto después.

Sintaxis

Las fábricas pueden invocarse de varias maneras, la más frecuente es una llamada a un método (un método de fábrica ), a veces se las llama como una función si la fábrica es un objeto invocable (una función de fábrica ). En algunos lenguajes, los constructores y las fábricas tienen una sintaxis idéntica, mientras que en otros los constructores tienen una sintaxis especial. En lenguajes donde los constructores y las fábricas tienen una sintaxis idéntica, como Python, Perl, Ruby, Object Pascal y F#, los constructores [e] pueden reemplazarse de forma transparente por fábricas. En lenguajes donde difieren, se deben distinguir en las interfaces, y cambiar entre constructores y fábricas requiere cambiar las llamadas.

Semántica

En lenguajes donde los objetos se asignan dinámicamente , como en Java o Python, las fábricas son semánticamente equivalentes a los constructores. Sin embargo, en lenguajes como C++ que permiten que algunos objetos se asignen estáticamente, las fábricas son diferentes de los constructores para clases asignadas estáticamente, ya que estos últimos pueden tener una asignación de memoria determinada en tiempo de compilación, mientras que la asignación de los valores de retorno de las fábricas debe determinarse en tiempo de ejecución. Si un constructor se puede pasar como argumento a una función, entonces la invocación del constructor y la asignación del valor de retorno deben realizarse dinámicamente en tiempo de ejecución y, por lo tanto, tienen una semántica similar o idéntica a la invocación de una fábrica.

Patrones de diseño

Las fábricas se utilizan en varios patrones de diseño , en concreto en patrones de creación como la biblioteca de objetos de patrones de diseño. Se han desarrollado recetas específicas para implementarlas en muchos lenguajes. Por ejemplo, varios patrones "GoF ", como el " Factory method pattern ", el " Builder " o incluso el " Singleton " son implementaciones de este concepto. El " Abstract factory pattern ", en cambio, es un método para construir colecciones de fábricas.

En algunos patrones de diseño, un objeto de fábrica tiene un método para cada tipo de objeto que puede crear. Estos métodos aceptan opcionalmente parámetros que definen cómo se crea el objeto y luego devuelven el objeto creado.

Aplicaciones

Los objetos de fábrica son comunes en los conjuntos de herramientas y los marcos de trabajo donde el código de la biblioteca necesita crear objetos de tipos que pueden ser subclasificados por las aplicaciones que utilizan el marco de trabajo. También se utilizan en el desarrollo basado en pruebas para permitir que las clases se pongan a prueba. [8]

Las fábricas determinan el tipo concreto real del objeto que se va a crear y es aquí donde se crea realmente el objeto. Como la fábrica solo devuelve una interfaz abstracta al objeto, el código del cliente no conoce (y no se ve afectado por) el tipo concreto real del objeto que se acaba de crear. Sin embargo, la fábrica abstracta conoce el tipo de un objeto concreto. En particular, esto significa:

Aplicabilidad

Las fábricas se pueden utilizar cuando:

  1. La creación de un objeto hace imposible su reutilización sin una duplicación significativa de código.
  2. La creación de un objeto requiere acceso a información o recursos que no deberían estar contenidos dentro de la clase que lo compone.
  3. La gestión del tiempo de vida de los objetos generados debe estar centralizada para garantizar un comportamiento consistente dentro de la aplicación.

Las fábricas, específicamente los métodos de fábrica, son comunes en los kits de herramientas y los marcos , donde el código de la biblioteca necesita crear objetos de tipos que pueden ser subclasificados por aplicaciones que usan el marco.

Las jerarquías de clases paralelas a menudo requieren que los objetos de una jerarquía puedan crear objetos apropiados de otra.

Los métodos de fábrica se utilizan en el desarrollo basado en pruebas para permitir que las clases se pongan a prueba. [9] Si una clase de este tipo Foocrea otro objeto Dangerousque no se puede poner a prueba en pruebas unitarias automatizadas (quizás se comunica con una base de datos de producción que no siempre está disponible), entonces la creación de Dangerousobjetos se coloca en el método de fábrica virtualcreateDangerous en la clase Foo. Para las pruebas, se crea TestFoo(una subclase de ), con el método de fábrica virtual anulado para crear y devolver , un objeto falso . Las pruebas unitarias luego se utilizan para probar la funcionalidad de sin incurrir en el efecto secundario de usar un objeto real.FoocreateDangerousFakeDangerousTestFooFooDangerous

Beneficios y variantes

Además de su uso en patrones de diseño, las fábricas, especialmente los métodos de fábrica, tienen varios beneficios y variaciones.

Nombres descriptivos

Un método de fábrica tiene un nombre distintivo. En muchos lenguajes orientados a objetos, los constructores deben tener el mismo nombre que la clase en la que se encuentran, lo que puede generar ambigüedad si hay más de una forma de crear un objeto (consulte sobrecarga ). Los métodos de fábrica no tienen esa restricción y pueden tener nombres descriptivos; a veces se los conoce como constructores alternativos . A modo de ejemplo, cuando se crean números complejos a partir de dos números reales, los números reales se pueden interpretar como coordenadas cartesianas o polares, pero al utilizar métodos de fábrica, el significado es claro, como lo ilustra el siguiente ejemplo en C#.

clase pública Complejo { público doble _real ; público doble _imaginario ;         público estático Complejo FromCartesian ( doble real , doble imaginario ) { devolver nuevo Complejo ( real , imaginario ); }             public static Complex FromPolar ( doble módulo , doble ángulo ) { return new Complex ( módulo * Math.Cos ( ángulo ) , módulo * Math.Sin ( ángulo ) ) ; }                 privado Complejo ( doble real , doble imaginario ) { este . _real = real ; este . _imaginario = imaginario ; } }            Producto complejo = Complex . FromPolar ( 1 , Math . PI );    

Cuando se utilizan métodos de fábrica para desambiguación como esta, los constructores sin procesar a menudo se hacen privados para obligar a los clientes a utilizar los métodos de fábrica.

Encapsulación

Los métodos de fábrica encapsulan la creación de objetos. Esto puede resultar útil si el proceso de creación es muy complejo; por ejemplo, si depende de ajustes en archivos de configuración o de la entrada del usuario.

Consideremos como ejemplo un programa que lee archivos de imagen . El programa admite distintos formatos de imagen, representados por una clase de lector para cada formato.

Cada vez que el programa lee una imagen, necesita crear un lector del tipo apropiado en función de cierta información del archivo. Esta lógica se puede encapsular en un método de fábrica. Este enfoque también se conoce como Fábrica simple.

Java

clase pública ImageReaderFactory { public static ImageReader createImageReader ( ImageInputStreamProcessor iisp ) { if ( iisp.isGIF ( ) ) { return new GifReader ( iisp.getInputStream ( ) ); } else if ( iisp.isJPEG ( ) ) { return new JpegReader ( iisp.getInputStream ( ) ); } else { throw new IllegalArgumentException ( "Tipo de imagen desconocido." ); } } }                               

PHP

clase  Factory {  función pública  estática  build ( cadena $type ) : FormatInterface { $class = "Format" . $type ; devolver nueva $class ; } }             Interfaz  FormatoInterfaz  {}La clase  FormatString  implementa  FormatInterface  {} La clase  FormatNumber  implementa  FormatInterface  {}intentar  {  $string  =  Factory :: build ( "String" ); }  catch  ( Error  $e )  {  echo  $e -> getMessage (); }intentar  {  $número  =  Fábrica :: build ( "Número" ); }  catch  ( Error  $e )  {  echo  $e -> getMessage (); }

Limitaciones

Existen tres limitaciones asociadas con el uso del método de fábrica. La primera se relaciona con la refactorización del código existente; las otras dos se relacionan con la extensión de una clase.

Una vez que nos damos cuenta de que se necesitan dos fábricas diferentes, cambiamos la clase (al código que se mostró anteriormente). Pero como el constructor ahora es privado, el código del cliente existente ya no se compila.

Los tres problemas podrían aliviarse modificando el lenguaje de programación subyacente para convertir a las fábricas en miembros de clase de primera clase (véase también Clase virtual ). [10]

Notas

  1. ^ En términos de interfaz, cualquier objeto que devuelva un objeto puede usarse como una fábrica, pero semánticamente una fábrica devuelve un objeto recién creado, como una instancia de clase o una copia de un prototipo, o un objeto que parece nuevo, como un objeto reinicializado de un grupo de objetos.
  2. ^ En los lenguajes donde los constructores son en sí mismos métodos de un objeto de clase ( métodos de clase ), existe un objeto existente y los constructores son casos especiales de métodos de fábrica, siendo la creación polimórfica un caso especial de envío de métodos polimórficos. En otros lenguajes existe una clara distinción entre constructores y métodos.
  3. ^ Los constructores se pueden utilizar en cualquier lugar donde se puedan utilizar fábricas, ya que son un caso especial.
  4. ^ Esta clase es una subclase de dict, la implementación incorporada de Python de asignaciones o diccionarios.
  5. ^ Si se omite la palabra clave opcional .new

Referencias

  1. ^ Gamma, Erich (1994). Patrones de diseño . Addison-Wesley. págs. 18-19. ISBN 9780321700698.
  2. ^ "Patrón de fábrica", OODesign.com
  3. ^ Patrón de fábrica, WikiWikiWeb
  4. ^ ab Capítulo 4. El patrón de fábrica: Hornear con bondades OO Archivado el 11 de marzo de 2017 en Wayback Machine : La fábrica simple definida Archivado el 19 de febrero de 2014 en Wayback Machine
  5. ^ "30.8 Las clases son objetos: fábricas de objetos genéricos", Aprendiendo Python, por Mark Lutz, 4.ª edición, O'Reilly Media, Inc., ISBN 978-0-596-15806-4 
  6. ^ Método de fábrica, WikiWikiWeb
  7. ^ objetos defaultdict
  8. ^ Feathers, Michael (octubre de 2004). Cómo trabajar eficazmente con código heredado . Upper Saddle River, NJ: Referencia técnica profesional de Prentice Hall. ISBN 978-0-13-117705-5.
  9. ^ Feathers, Michael (octubre de 2004), Cómo trabajar eficazmente con código heredado , Upper Saddle River, NJ: Prentice Hall Professional Technical Reference, ISBN 978-0-13-117705-5
  10. ^ Agerbo, Ellen; Cornils, Aino (1998). "Cómo preservar los beneficios de los patrones de diseño". Conferencia sobre lenguajes y aplicaciones de sistemas de programación orientados a objetos . Vancouver, Columbia Británica, Canadá: ACM: 134–143. ISBN 1-58113-005-8.