Você está na página 1de 23

Patrones de Fabricacin: Fbricas de Objetos

Contenido
1. Introduccin
1.1. Fbricas
1.2. Factory Method vs. Creation Methods
1.3. Relacin entre los Patrones de Factora
2. Factory Method
2.1. Definicin del Patrn
2.2. Breve Discusin
2.3. Ejemplo "No Software"
2.4. Ejemplos en .net Framework
2.5. Ejemplos de Cdigo
2.5.1. Variaciones de Factory Method
2.5.1.1. Creador es una Clase Abstracta o Interface
2.5.1.2. Creador es una Clase Concreta con Implementacin Predeterminada
2.5.1.3. Mtodos de Fabricacin Parametrizados
2.5.1.4. Lazy Initialization
2.5.1.5. Combinacin de Factory Method y Template Method
3. Abstract Factory
3.1. Definicin del Patrn
3.2. Breve Discusin
3.3. Factory Method y Abstract Factory
3.4. Ejemplo "No Software"
3.5. Ejemplos en .net
3.6. Ejemplo de Cdigo
4. Factory Pattern (Simple Factory)
4.1. Ejemplos de Cdigo
4.2. Por qu estas Clases no se engloban en los Patrones Anteriores?
4.2.1. Simple Factory y Factory Method
4.2.2. Simple Factory y Abstract Factory
5. Conclusin: Flexibilidad y Complejidad
Referencias y Bibliografa
1. Introduccin
En este artculo analizaremos los patrones de fabricacin ms conocidos. Llamamos patrones de fabricacin a aquellos patrones que
involucran algn tipo de factora o fbrica (factory, en ingls) de objetos. Estos patrones entran en la categora de patrones de
creacin [GoF95], la cual comparten con otros patrones tales como el Singleton, Builder y Prototype [GoF95].
Los objetos de fabricacin (fbricas) tienen la responsabilidad de crear instancias de objetos de otras clases. Tienen adems la
responsabilidad y el conocimiento necesario para encapsular la forma en que se crean determinados tipos de objetos en una
aplicacin.
Existen diferentes patrones de fabricacin. En este artculo, trataremos Abstract Factory, Factory Method, y Simple Factory. Los
dos primeros estn incluidos en el catlogo del GoF (presentado y analizado en la entrega anterior) y sern tratados en mayor
profundidad.

1.1. Fbricas
Para comenzar con nuestro estudio debemos definir claramente qu es una factora o fbrica. De la misma forma que sucede con
muchos conceptos en la Ingeniera del Software, existen varias definiciones para este trmino (en la entrega anterior hemos
experimentado esta situacin para el concepto de patrn); por tanto, es fundamental clarificar este concepto para sentar las bases de
nuestro estudio posterior.
El trmino factory (o fbrica) adolece de ser sobreutilizado e impreciso. Mucha gente se refiere a factory para indicar una
implementacin de Factory Method o de Abstract Factory (patrones definidos en el libro del GoF). Otros sin embargo, se refieren
a un objeto que crea instancias de otros, aunque no sigue las reglas de los patrones mencionados anteriormente.
La falta de consenso sobre el trmino dificulta la comunicacin que, como ya hemos visto anteriormente, es uno de los objetivos de
los patrones (poder referirse en forma unvoca a una abstraccin de mayor nivel que la clase individual, incrementando as el
vocabulario de los ingenieros de software). Recordemos entonces una importante frase de la entrega anterior:
Los Patrones permiten establecer un vocabulario comn de diseo, cambiando el nivel de abstraccin a colaboraciones entre clases
y permitiendo comunicar experiencia sobre dichos problemas y soluciones. Son tambin un gran mecanismo de comunicacin para
transmitir la experiencia de los ingenieros y diseadores experimentados a los ms nveles, convirtindose en unas de las vas para
la gestin del conocimiento.
Por tanto, es muy importante establecer un significado claro para este trmino, a los efectos de construir este vocabulario comn.
Llamaremos fbrica, factora o factory a una clase que implemente uno o ms mtodos de creacin, que son los mtodos que se
encargan de crear instancias de objetos (estas instancias pueden ser de esta misma clase o de otras). Esta clase tiene entre sus
responsabilidades la creacin de instancias de objetos, pero puede tener tambin otras responsabilidades adicionales. Los mtodos de
creacin pueden ser estticos.
Existen diferentes "tipos" de fbricas. A continuacin enumeraremos cada una de ellos, a los efectos de dejar bien en claro sus
significados:
Simple Factory
Clase utilizada para crear nuevas instancias de objetos.
Factory Method
Define una interfaz para crear objetos pero deja que sean las subclases las que deciden qu clases instanciar.
Abstract Factory
Proporciona una interfaz para crear familias de objetos relacionados o que dependen entre s, sin especificar sus clases concretas.
En la Figura 1 se muestra los diferentes tipos de factoras con las que trabajaremos en este artculo. En cada caso, cada cuadro
representa una clase y cada lnea es un mtodo en esa clase:

Figura 1: Tipos de fbricas, inspirado en [Kerievsky04]. Volver al texto.


A lo largo de este artculo estudiaremos en mayor profundidad cada uno de estos patrones.
1.2 Factory Method vs. Creation Methods
Cmo llamar a un mtodo que crea instancias de otras clases? Muchas veces se lo llama Factory Method, aunque esto puede
prestarse a malos entendidos, dado que puede confundirse con el patrn del GoF homnimo. Por lo tanto, llamaremos a los mtodos
(o funciones) encargadas de crear instancias de otras clases Creation Methods (mtodos de creacin) a los efectos de establecer
claramente esta diferenciacin.
En la Figura 2 se muestra la relacin entre los conceptos Factory Method y Creation Method:

Figura 2: Relacin entre Factory Method y Factory Function; Factory Method contiene varios Creation Methods (mtodos de
creacin). Volver al texto.

1.3 Relacin entre los Patrones de Factora


Los patrones no existen aislados el uno del otro, sino ms bien dentro del contexto de un lenguaje o sistema de patrones. Por
consiguiente existen relaciones entre ellos que pueden determinar cundo, cmo y por qu utilizar uno u otro. Los patrones de
fabricacin no estn exentos de esto.
En el libro del GoF por ejemplo, se indica que el patrn Abstract Factory se implementa utilizando Factory Method. A su vez, ambos
patrones estn relacionados con otros patrones del catlogo. En la Figura 3 se muestran las relaciones entre patrones de creacin que
existen dentro del catlogo del GoF [GoF95]:

Figura 3: Relaciones entre los patrones de creacin del catlogo del GoF (tomada de [GoF95]). Hemos marcado con un borde rojo
los patrones que tratamos en este artculo (Abstract Factory y Factory Method). Volver al texto.
En la Figura 4 se representa la forma en que estn relacionados todos los conceptos referentes a las fbricas estudiados hasta ahora:

Figura 4: Diagrama basado en UML que muestra las relaciones entre los distintos patrones tratados en este artculo. Volver al texto.
En la vida real, los patrones no estn segregados por lneas absolutas. A menudo, una clase puede utilizar uno o ms patrones,
haciendo difuso el lmite entre ambos. Adicionalmente, se puede comenzar utilizando un patrn sencillo y evolucionar hacia otro
ms complejo en funcin de las necesidades de nuestra aplicacin
Principio de la pgina

2. Factory Method
Factory Method define una interfaz para crear objetos, pero deja que sean las subclases quienes decidan qu clases instanciar;
permite que una clase delegue en sus subclases la creacin de objetos.
2.1 Definicin del Patrn
A continuacin presentaremos una versin reducida de la plantilla de este patrn. Para obtener la versin completa, consulta el libro
del GoF:
Problema
Una clase necesita instanciar otra clase derivada de una tercera clase, pero no sabe cul. Factory Method permite a la clase derivada
tomar esta decisin.
Solucin
Una clase derivada toma la decisin sobre qu clase instanciar y cmo instanciarla (Ver Figura 5):

Figura 5: Diagrama OMT de Factory Method, tomado del libro del GoF. Volver al texto.
Participantes
Producto
Define la interfaz de los objetos que crea el mtodo de fabricacin.
ProductoConcreto
Implementa la interfaz Producto.
Creador
Declara el mtodo de fabricacin, el cual devuelve un objeto del tipo Producto. Tambin puede definir una implementacin
predeterminada del mtodo de fabricacin que devuelve un objeto ProductoConcreto. Puede llamar al mtodo de fabricacin para
crear un objeto Producto.
CreadorConcreto
Redefine el mtodo de fabricacin para devolver una instancia de ProductoConcreto.

Aplicabilidad
Usar cuando:

Una clase no puede prever la clase de objetos que debe crear.

Una clase quiere que sean sus subclases quienes especifiquen los objetos que sta crea.

Las clases delegan la responsabilidad en una de entre varias clases auxiliares, y queremos localizar concretamente en qu
subclase de auxiliar se delega.

Consecuencias
Proporciona enganches para las subclases. Crear objetos dentro de una clase con un mtodo de fabricacin es siempre ms flexible
que hacerlo directamente. Conecta jerarquas de clases paralelas.
Resumen 1: Vista simplificada y resumida del patrn Factory Method, tomado de [GoF95] y [DPE01]
2.2 Breve Discusin
El patrn Factory Method permite escribir aplicaciones que son ms flexibles respecto de los tipos a utilizar difiriendo la creacin
de las instancias en el sistema a subclases que pueden ser extendidas a medida que evoluciona el sistema. Permite tambin
encapsular el conocimiento referente a la creacin de objetos. Factory Method hace tambin que el diseo sea ms adaptable a
cambio de slo un poco ms de complejidad. Se utiliza frecuentemente con Template Method. En la seccin de ejemplos de cdigo
de este patrn presentaremos una implementacin de este caso.
Uno de los principales inconvenientes que puede presentar este patrn es que puede requerir crear una nueva clase simplemente para
cambiar la clase de Producto.
2.3 Ejemplo "No Software"
En [Duell97] se presenta el siguiente ejemplo:
Las prensas de moldeado a inyeccin sirven para explicar este patrn. Los fabricantes de juguetes de plstico procesan plstico en
polvo para moldeado, e inyectan el plstico en moldes con las formas deseadas. La clase de un juguete (auto, figura, etc.) es
determinada por el molde.
En la Figura 6 se muestra un diagrama UML de este ejemplo:

Figura 6: Ejemplo del mundo real del patrn Factory Method, tomado de [Duell97]. Volver al texto.

2.4 Ejemplos en .net Framework


En .net podemos encontrar varias implementaciones de este patrn. A modo de ejemplo, hemos tomado una de ASP .net 1.1,
concretamente, la implementacin del gestor de manejadores (handlers).
En la Figura 7 se muestra el diagrama del GoF actualizado con objetos del Framework .net; en este caso los del ejemplo
seleccionado:

Figura 7: Ejemplo de implementacin del patrn Factory Method en ASP .net. Volver al texto.
2.5 Ejemplos de Cdigo
Existe un nmero de variantes para este patrn. En esta seccin enumeraremos y explicaremos las principales y ofreceremos
ejemplos en C# para cada caso.
Para los ejemplos, utilizaremos como clases Producto un modelo de objetos muy sencillo de una tienda de mascotas. En este caso,
Mascota hace las veces del participante Producto; y Perro, Gato y Vbora son instancias de Producto Concreto (Ver Figura 8):

Figura 8: Modelo de objetos Producto utilizados en los ejemplos de implementacin del patrn Factory Method. Volver al texto.
2.5.1 Variaciones de Factory Method
Si bien existen diversas variaciones en la implementacin de este patrn, los dos principales casos son los que se indican a
continuacin:

Creador es abstracto y no provee una implementacin para el mtodo de creacin que declara.

Creador es una clase concreta y provee una implementacin predeterminada para el mtodo de creacin que declara.

En las siguientes secciones presentaremos las distintas opciones de implementacin de este patrn y para cada una de ellas
ofreceremos un ejemplo en C#.

2.5.1.1 Creador es una Clase Abstracta o Interfaz


En este caso, el creador es una clase abstracta o interfaz (siempre que sea posible, es ms recomendable utilizar una interfaz) y no
provee una implementacin predeterminada. Por lo tanto, son las clases derivadas las que tienen la responsabilidad sobre la
implementacin de la funcin de creacin.
En el ejemplo que se muestra a continuacin existe un creador que crea instancias de Perro y otro que crea instancias de Gato,
ambos basados en la misma interfaz:
/// <summary>
/// Creador sin implementacin. Puede ser una interfase
/// o una clase abstracta, donde los mtodos de creacin
/// no tienen implementacin
/// </summary>
public interfase ICreador
{
/// <summary>
/// Mtodo de creacin
/// </summary>
/// <returns>Instancia de una mascota</returns>
Mascota Crear();
}
/// <summary>
/// Creador Concreto. Implementa la interfase de creacin
/// </summary>
public class CreadorConcreto: ICreador
{
/// <summary>
/// Mtodo de creacin
/// </summary>
/// <returns>Instancia de una mascota</returns>
public Mascota Crear()
{
return new Perro();
}
}
/// <summary>
/// Otra instancia de Creador Concreto.
/// Implementa la interfase de creacin
/// </summary>
public class OtroCreadorConcreto: ICreador
{
/// <summary>
/// Mtodo de creacin. En este caso, retorna
/// un una instancia de una mascota de la clase Gato
/// </summary>
/// <returns>Instancia de una mascota</returns>
public Mascota Crear()
{
return new Gato();
}
}

Cdigo 1 - Ejemplo de Factory Method donde el Creador es una interfaz. En este ejemplo de cdigo, existen 2 creadores concretos
que son las clases que implementan la interfase ICreador. Cada creador crea un subtipo diferente de Mascota, por ejemplo, Perro
en el primer caso y Gato en el segundo.
2.5.1.2 Creador es una Clase Concreta con Implementacin Predeterminada
En este caso, la clase base provee una implementacin predeterminada de la funcin de creacin. Por lo tanto, las clases hijas
pueden re-implementarla o utilizar la implementacin provista por la clase base.
Para lograr este comportamiento, la funcin de creacin en la clase base debe marcarse como virtual (esto significa que puede ser
redefinida por las clases derivadas).
En el ejemplo a continuacin veremos como la clase base crea instancias de objetos de tipo Perro y la subclase, en cambio, crea
instancias de Gato (redefiniendo la implementacin del mtodo de creacin del tipo base):
/// <summary>
/// Creador. Esta es la clase base del Factory Method.
/// Provee una implementacin default del mtodo de creacin,
/// que puede ser redefinida por los mtodos hijos
/// </summary>
public class Creador
{
/// <summary>
/// Metodo de creacin
/// </summary>
/// <returns>Instancia de una mascota</returns>
public virtual Mascota Crear()
{
return new Perro();
}
}
/// <summary>
/// Creador Concreto. Redefine el mtodo de creacin
/// definido en Creador, cambiando el "ProductoConcreto"
/// que se retorna
/// </summary>
public class CreadorConcreto: Creador
{
/// <summary>
/// Metodo de creacin
/// </summary>
/// <returns>Instancia de una mascota</returns>
public override Mascota Crear()
{
return new Gato();
}
}
Cdigo 2 - Ejemplo de Factory Method donde Creador es una clase concreta y tiene implementacin predeterminada. Creador
provee una implementacin predeterminada que es redefinida por los creadores concretos. En el ejemplo, CreadorConcreto
redefine el mtodo Crear, retornando una instancia de otra subclase de Mascota (concretamente Gato en lugar de Perro).

2.5.1.3 Mtodos de Fabricacin Parametrizados


Otra variacin del patrn permite que la funcin de creacin cree mltiples instancias de Producto. La funcin recibe como entrada
un parmetro que identifica el tipo de objeto a crear. Todos los objetos creados por esta funcin deben ser subclases de Producto.
En el ejemplo que se muestra a continuacin, se crea una mascota en funcin de un parmetro con el nombre del tipo de Mascota.
En este mismo ejemplo se crea una subclase de Creador (un creador concreto) muy quisquilloso: slo puede crear instancias de
mascotas de tipo Perro. En los dems casos dispara una excepcin, explicando el motivo por el cual no ha podido crear la instancia:
/// <summary>
/// Creador. Esta es la clase base del Factory Method.
/// Provee una implementacin default del mtodo de creacin,
/// que puede ser redefinida por los mtodos hijos. El mtodo
/// de creacin acepta parmetros, permitiendo crear diferentes
/// instancias de mascotas
/// </summary>
public class Creador
{
/// <summary>
/// Funcin de creacin de ordenadores. Recibe el tipo
/// de ordenador a crear y retorna una instancia valida
/// </summary>
/// <remarks>
/// Dado que la funcin es virtual, puede ser modificada
/// sus las clases hijas
/// </remarks>
/// <param name="tipo">Tipo de ordenador (producto) a crear</param>
/// <returns>Instancia valida de ordenador (producto)</returns>
public virtual Mascota Crear(string tipo)
{
switch (tipo.ToLower())
{
case "perro":
return new Perro();
case "gato":
return new Gato();
case "vibora":
return new Vibora();
default:
throw new ArgumentException("Tipo de mascota desconocido");
}
}
}

/// <summary>

/// Creador Concreto. Redefine el mtodo de creacin definido en Creador,


/// cambiando el "ProductoConcreto" que se retorna. En este caso,
/// slo permite crear mascotas del tipo "Perro". En los dems casos,
/// dispara una excepcin
/// </summary>
public class CreadorConcreto: CreadorParametrizado
{
/// <summary>
/// Funcin de creacin de ordenadores. Solo permite
/// crear Mascotas de tipo Perro.
/// </summary>
/// <remarks>
/// Esta funcin redefine a la funcin anterior, cambiando
/// el comportamiento de creacin en funcin del mtodo
/// </remarks>
/// <param name="tipo">Tipo de ordenador (producto) a crear</param>
/// <returns>Instancia valida de ordenador (producto)</returns>
public override Mascota Crear(string tipo)
{
switch (tipo.ToLower())
{
case "perro":
return new Perro();
case "gato":
throw new ArgumentException("Soy alrgico a los gatos.");
case "vbora":
throw new ArgumentException("No se puede tener una vbora como mascota.");
default:
throw new ArgumentException("Tipo de mascota desconocido");
}
}
}
Cdigo 3 - Ejemplo de Factory Method con el mtodo de creacin parametrizado. Nota que el mtodo de creacin adems de recibir
un parmetro est marcado como virtual, para poder ser redefinido en las clases hijas.
2.5.1.4 Lazy Initialization
En algunos casos, por ejemplo cuando la creacin de la instancia tiene un coste elevado, se puede mantener una referencia a una
instancia vlida, la cual slo es creada la primera vez que se solicita. Por lo tanto, slo incurrimos en el coste de creacin una nica
vez. A continuacin se muestra un ejemplo de cmo implementar esta tcnica:
/// <summary>
/// Creador. Esta es la clase base del patrn Factory Method.
/// Provee una implementacin default del mtodo de creacin,
/// que puede ser redefinida por los mtodos hijos. El mtodo
/// de creacion utiliza Lazy Instantiation.
/// </summary>
public class Creador
{
// instancia de "Producto"
private Mascota producto;

/// <summary>
/// Mtodo de creacin.
/// </summary>

/// <remarks>
/// Es un "TemplateMethod". Para modificar la clase a instanciar,
/// se debe modificar en las clases hijas el mtodo CrearOrdenador
/// </remarks>
/// <returns>Instancia de Mascota</returns>
public Mascota Crear()
{
/// si no se ha creado el producto, lo creamos
if (this.producto == null)
this.CrearMascota();
/// retorna la instancia del producto
return this.producto;
}
/// <summary>
/// Mtodo real de fabricacin.
/// </summary>
/// <remarks>
/// Este mtodo que crea la instancia. Es el que debe ser redefinido
/// en las clases hijas para modificar la clase del objeto a crear
/// </remarks>
protected virtual void CrearMascota()
{
this.producto = new Perro();
}
}
Cdigo 4 - Ejemplo de Factory Method utilizando Lazy Load.
Otro aspecto interesante a notar es la utilizacin del patrn Template Method [GoF95] para seleccionar el tipo de la instancia a
crear. La funcin CrearMascota funciona como Template Method: este mtodo tiene el comportamiento variable, mientras que
crear tiene el comportamiento que no vara. Por lo tanto, si quisiramos crear una subclase para crear instancias de otro tipo de
Mascota (por ejemplo Gato), slo tendramos que redefinir el mtodo CrearMascota.
2.5.1.5 Combinacin de Factory Method y Template Method
El patrn Template Method "define en una operacin el esqueleto de un algoritmo, delegando en las subclases algunos de sus
pasos. Permite que las subclases redefinan ciertos pasos de un algoritmo sin cambiar su estructura" [GoF95]. En el ejemplo que se
muestra a continuacin mostramos cmo combinar estos dos patrones.
Para demostrar esto con un ejemplo, implementaremos un cuidador de mascotas. El cuidador tiene la responsabilidad de alimentar y
pasear a nuestras mascotas. Su comportamiento puede describirse de la siguiente forma:
1.

Obtiene una mascota para cuidar.

2.

La alimenta.

3.

Si tiene 2 ms patas, la lleva a pasear.

Las clases Cuidador y CuidadorDePerros combinan a los patrones Factory Method y Template Method. La clase Cuidador
cumple los roles de Creador en Factory Method y Abstract Class en Template Method.
El mtodo Cuidar tiene el comportamiento fijo y no puede ser redefinido en las clases hijas. Recordando la definicin del patrn,
este mtodo contiene "la estructura del algoritmo". El mtodo abstracto CrearMascota, en cambio, es un mtodo de creacin (en
Factory Method) y una operacin primitiva (en Template Method). En ambos casos este mtodo debe ser redefinido en las clases
derivadas.
La clase CuidadorDePerros muestra un ejemplo de cmo puede crearse un cuidador que sepa tratar con perros:

/// <summary>
/// Esta es la clase que implementa Template Method
/// y Factory Method. En el caso de Factory Method,
/// hemos implementado la opcin donde el creador
/// es una clase abstracta
/// </summary>
public abstract class Cuidador
{
/// <summary>
/// Este es el template method. Este mtodo es
/// el que tiene la lgica y no se redefine en
/// las clases hijas
/// </summary>
public void Cuidar()
{
/// obtenemos una instancia de una mascota
Mascota mascota = this.CrearMascota();
/// alimentamos a la mascota
mascota.Alimentar();
/// si la mascota tiene mas de 2 patas, la llevamos a pasear
if (mascota.CantidadPatas > 1)
mascota.Pasear();
}
/// <summary>
/// Este es el mtodo de creacin (para el Factory Method)
/// y la Operacin Primitiva que debe ser
/// redefinida por el usuario (para el Template Method)
/// </summary>
/// <returns>Instancia de Mascota</returns>
public abstract Mascota CrearMascota();
}
/// <summary>
/// Creador Concreto. Solo redefine la operacin de creacin, pero hereda
/// el comportamiento fijo de CreadorTemplateMethod
/// </summary>
public class CuidadorDePerro: CreadorTemplateMethod
{
/// <summary>
/// Mtodo de creacin, redefinido de la clase base
/// </summary>
/// <returns>Instancia de Mascota</returns>
public override Mascota CrearMascota()
{
return new Perro();
}
}

Cdigo 5 - Ejemplo de combinacin de Factory Method y Template Method.

Es importante destacar que este cdigo es un ejemplo ilustrativo y por lo tanto puede carecer de sentido en el mundo real, dado que
el cuidador cuida siempre "nuevas instancias de perros". Este ejemplo podra mejorarse creando una subclase de cuidador que
obtenga la instancia de Mascota a partir de una serie de criterios arbitrarios. Las tcnicas que estamos utilizando permiten probar
nuevas alternativas sin afectar al cdigo existente (por ejemplo, podramos crear una subclase de cuidador, probarla y mejorarla sin
necesidad de modificar a las clases CuidadorDePerros o Cuidador).
Principio de la pgina
3. Abstract Factory
El patrn Abstract Factory proporciona una interfaz para crear familias de objetos relacionados o que dependen entre s, sin
especificar sus clases concretas.
3.1 Definicin del Patrn
Intencin
Proporciona una interfaz para crear familias de objetos relacionados o que dependen entre s, sin especificar sus clases concretas.
Problema
Se necesita instanciar familias de objetos.
Solucin
Coordinar la creacin de familias de objetos. Establecer una forma para quitar las reglas de cmo realizar la instanciacin fuera del
objeto que est usando los objetos a crear. (Ver Figura 9):

Figura 9: Diagrama OMT de Factory Method, tomado del libro del GoF. Volver al texto.

Participantes

FabricaAbstracta
Declara una interfaz para operaciones que crean objetos producto abstractos.
FabricaConcreta
Implementa las operaciones para crear objetos producto concretos.
ProductoAbstracto
Declara una interfaz para un tipo de objeto producto.
ProductoConcreto
Define un objeto producto para que sea creado por la fbrica correspondiente. Implementa la interfase ProductoAbstracto.
Cliente
Slo usa interfaces declaradas por las clases FabricaAbstracta y ProductoAbstracto.
Aplicabilidad
Usar cuando:

Un sistema debe ser independiente de cmo se crean, componen y representan sus productos.

Un sistema debe ser configurado con una familia de productos entre varias.

Una familia de objetos producto relacionados est diseada para ser usada conjuntamente y es necesario hacer cumplir esa
restriccin.

Se quiere proporcionar una biblioteca de clases de productos y slo se quiere revelar sus interfaces, no sus
implementaciones.

Consecuencias

Asla las clases concretas.

Facilita el intercambio de familias de productos.

Promueve la consistencia entre productos.

Desventaja: Es difcil dar cabida a nuevos tipos de productos.

Resumen 2 - Vista simplificada y resumida del patrn Abstract Factory, tomado de [GoF95] y [DPE01].
3.2 Breve Discusin
Abstract Factory puede ser utilizado para desarrollar frameworks y sistemas que pueden ser configurados con una de mltiples
familias de productos.
Provee un nivel adicional de indireccin que abstrae la creacin de familias de objetos relacionados o dependientes sin especificar
sus clases concretas. El objeto "fbrica" tiene la responsabilidad de proveer la funcionalidad y el protocolo para la creacin de la
familia completa. Los clientes nunca deben crear objetos directamente, sino a travs de la factora. Por consiguiente, es fcil cambiar

las familias de productos que se utilizan, porque el tipo especfico de cada instancia aparece slo una vez en la aplicacin: en el
mtodo de creacin donde se crea la instancia.

Como hemos dicho anteriormente, este patrn es utilizado cuando se desean crear familias de productos, pero... Qu queremos
decir con familias de productos? Imaginemos que tenemos una aplicacin y queremos que pueda mostrarse en mltiples sistemas de
ventanas como por ejemplo Windows 9x, 2000, XP, Mac OS y X-Windows. Cuando creamos los diferentes controles de usuario, es
muy importante que se creen en forma consistente. Por ejemplo, en una ventana no queremos que se mezclen botones tipo Windows
95 con barras de desplazamiento de estilo MacOS. Por esto, debemos asegurarnos que todos los objetos de interfaz de usuario que
creemos pertenezcan a la misma familia (Windows 95, 2000, XP MacOS, etc.). El patrn Abstract Factory nos ayuda a resolver este
problema.
3.3 Factory Method y Abstract Factory
Abstract Factory generalmente se implementa utilizando Factory Method y por tanto provee al menos toda la flexibilidad de ste. La
diferencia principal entre ambos es que el primero trata con familias de productos, mientras que el otro se preocupa por un nico
producto.
Abstract Factory se encuentra a un nivel de abstraccin mayor que Factory Method.
Los diseos que usan Abstract Factory son ms flexibles que los que utilizan Factory Method, pero son tambin ms complejos.
Otra diferencia notable es el mbito de ambos patrones: Factory Method es un patrn de clase, mientras que Abstract Factory es un
patrn de objeto. Los patrones de clase se refieren a las relaciones entre las clases (estticas, en tiempo de compilacin) y sus
subclases mientras que los de objetos tratan sobre relaciones entre instancias (dinmicas, en tiempo de ejecucin). Los patrones de
objetos suelen ser preferibles a los de clases, ya que se basan en el principio fundamental de usar composicin en lugar de la
herencia y en la delegacin. La mayora de los patrones del GoF tienen mbito de objeto. Para acceder a una discusin ms detallada
sobre este tema, ver [GoF95].
3.4 Ejemplo "No Software"
Este patrn se encuentra en el equipamiento de cuo de metal utilizado en las fbricas de automviles japonesas. El equipamiento de
cuo es un Abstract Factory que crea partes de un automvil. La misma maquinaria se utiliza para estampar la puerta derecha e
izquierda, defensa delantera y trasera, etc., para diferentes modelos de autos. Mediante el uso de rodillos para cambiar los fines de
estampado, las "clases concretas" producidas por la maquinaria pueden cambiarse en 3 minutos [Duell97].
En la Figura 10, que se muestra a continuacin, vemos un ejemplo de esta situacin (utilizando una notacin basada en UML):

Figura 10: Ejemplo del mundo real del patrn "Abstract Factory", tomado de . Volver al texto.
3.5 Ejemplos en .net
El patrn Abstract Factory se utiliza en forma intensiva en ADO .net. En la Figura 11 se muestra cmo ha sido implementado este
patrn en los objetos conexin de ADO .net:

Figura 11: Implementacin de Abstract Factory en las conexiones ADO .net. Las lneas discontinuas representan la relacin de
creacin (la notacin en este caso es OMT , la misma que se usa en el libro del GoF). Volver al texto.
En la figura anterior vemos cmo mediante la utilizacin del patrn nos aseguramos que los objetos que se creen a partir de un tipo
de conexin (Transaccin o Command) sean de la misma familia que la del objeto conexin (SqlClient, OracleClient, etc.)

3.6 Ejemplo de Cdigo


Para mostrar el uso de este patrn, codificaremos en C# el ejemplo que se presenta en la seccin Motivacin de la plantilla de este
patrn en el libro del GoF.
En este caso, se busca que todos los objetos grficos que se creen en una aplicacin que soporte mltiples sistemas de visualizacin
pertenezcan a la misma familia. De este manera, si creamos una ventana para ser mostrada en Windows, los controles de usuario
(scrollbar, textbox, etc) que utilizaremos en ella deben ser controles para Windows. Lo mismo debera suceder si estuviramos
presentando la aplicacin en un Mac.
En la figura Figura 12 se muestra el diagrama OMT del ejemplo:

Figura 12: Diagrama OMT del ejemplo de Abstract Factory para regir la creacin de objetos grficos en un sistema que soporta
visualizacin en mltiples sistemas de ventanas. Este diagrama ha sido tomado de la seccin Motivacin de este patrn en el libro
del GoF. Volver al texto.
A continuacin se muestra el cdigo C# para el diagrama anterior:
/// <summary>
/// Abstract Factory. En este caso, la hemos implementado usando
/// una interfase, aunque tambin puede ser una clase abstracta
/// </summary>
public interface IWidgetFactory
{
Window CreateWindow();
Scrollbar CreateScrollbar();
}
/// <summary>
/// Concrete Factory (Fabrica Concreta)
/// </summary>
public class WindowsWidgetFactory: IWidgetFactory
{
public Window CreateWindow()
{
return new WindowsWindow();
}

public Scrollbar CreateScrollbar()


{
return new WindowsScrollbar();
}
}
/// <summary>
/// Concrete Factory (Fabrica Concreta)
/// </summary>
public class MacWidgetFactory: IWidgetFactory
{
public Window CreateWindow()
{
return new MacWindow();
}
public Scrollbar CreateScrollbar()
{
return new MacScrollbar();
}
}
/// <summary>
/// Producto
/// </summary>
public abstract class Window
{
public abstract void Render();
}
/// <summary>
/// Producto
/// </summary>
public abstract class Scrollbar
{
public abstract void Render();
}
/// <summary>
/// Producto Concreto (Scrollbar para Windows)
/// </summary>
public class WindowsScrollbar: Scrollbar
{
public override void Render()
{
Console.WriteLine("Pintando Scrollbar de Windows...");
}
}
/// <summary>
/// Producto Concreto (Ventana para Windows)
/// </summary>
public class WindowsWindow: Window
{
public override void Render()
{
Console.WriteLine("Pintando Ventana de Windows...");
}
}

/// <summary>
/// Producto Concreto (Scrollbar para Mac)
/// </summary>
public class MacScrollbar: Scrollbar
{
public override void Render()
{
Console.WriteLine("Pintando Scrollbar de Mac...");
}
}
/// <summary>
/// Producto Concreto (Ventana para Mac)
/// </summary>
public class MacWindow: Window
{
public override void Render()
{
Console.WriteLine("Pintando Ventana de Mac...");
}
}
class TestClient
{
/// <summary>
/// Punto de entrada principal de la aplicacin.
/// </summary>
[STAThread]
static void Main(string[] args)
{
/// Creo los objetos para windows
IWidgetFactory factory = new WindowsWidgetFactory();
Scrollbar scrollbar = factory.CreateScrollbar();
Window window = factory.CreateWindow();
window.Render();
scrollbar.Render();
/// Ahora, lo mismo pero para Mac.
/// Al cambiar el tipo del factory, todos los objetos que
/// se crean mediante ella son de la misma familia
factory = new MacWidgetFactory();
scrollbar = factory.CreateScrollbar();
window = factory.CreateWindow();
window.Render();
scrollbar.Render();
}
}
Cdigo 6 - Ejemplo de implementacin de Abstract Factory. En el ejemplo hay tambin un cliente de prueba.
Principio de la pgina

4. Factory Pattern (Simple Factory)


Muchas veces, cuando la gente habla de factory pattern, se refiere a uno de los dos patrones que hemos estudiado anteriormente.
Sin embargo, hay casos que no son cubiertos por estos patrones como por ejemplo, clases con mtodos estticos de fabricacin o
fbricas concretas que tienen implementacin, pero sus mtodos no son redefinibles. En estos casos, estamos ante una
implementacin del patrn Simple Factory.
Hemos dejado este tipo de factoras para el final, dado que son ms fciles de entender y analizar que los otros patrones presentados
anteriormente en este artculo.
En este caso, estamos ante tipos que tienen la responsabilidad de crear instancias de objetos de otras clases, pero que no cumplen
con las premisas establecidas en los patrones anteriores.
4.1 Ejemplos de Cdigo
/// <summary>
/// Simple Factory
/// Ejemplo con mtodo de creacin esttico
/// </summary>
public class CreadorDePerros
{
public static Mascota Create ()
return new Perro();
}
}
/// <summary>
/// Ejemplo de Simple Factory
/// </summary>
public class CreadorDeGatos
{
public Mascota Create()
{
return new Gato();
}
}
Cdigo 7 - Ejemplo de implementacin de variaciones de Simple Factory. En el primer caso, el mtodo de creacin es esttico. Nota
que no pueden redefinirse los mtodos de fabricacin en ninguna de las dos clases.
4.2 Por qu estas Clases no se engloban en los Patrones Anteriores?
Quizs la primer pregunta que puedes hacerte al ver el Cdigo 7 es: Por qu estas clases no se corresponden con los patrones
anteriores? En este apartado intentaremos explicarlo ...
4.2.1 Simple Factory y Factory Method
Comencemos con Factory Method. Para ello es fundamental recordar la intencin de este patrn: Factory Method define una interfaz
para crear objetos, pero deja que sean las subclases las que decidan qu clases instanciar. Permite que una clase delegue en sus
subclases la creacin de objetos.
En los ejemplos presentados en el Cdigo 7, las clases no exponen una interfaz que pueda ser redefinida por clases que deriven de
sta. Por tanto, no pueden dejar que sean las subclases las que decidan qu clases instanciar ni delegar en las subclases la creacin de
objetos. En ambos casos esto se debe a que el comportamiento est definido en cada clase y no puede ser redefinido en sus clases
derivadas.
4.2.2 Simple Factory y Abstract Factory
Continuemos con Abstract Factory. De la misma forma que en el caso anterior, recordaremos la intencin de este patrn:
Proporciona una interfaz para crear familias de objetos relacionados o que dependen entre s, sin especificar sus clases concretas.
En los ejemplos presentados en el Cdigo 7, no exponen una interfaz para crear familias de objetos relacionados, dado que solo
crean un nico producto y tampoco pueden ser redefinidos por las clases derivadas.

Respecto a la restriccin de las familias, podras estar pensando como contra-argumento el siguiente ejemplo de cdigo:
/// <summary>
/// Ejemplo de Simple Factory
/// </summary>
public class Creador
{
public static IWindow CreateWindow()
{
return new WindowsWindow();
}
public static IScrollbar CreateScrollbar()
{
return new WindowsScrollbar();
}
}
Cdigo 8 - Ejemplo de implementacin de creacin de familias de productos con Simple Factory.
En este nuevo ejemplo, nuestro creador s crea familias de productos, aunque tiene los siguientes inconvenientes:
1.

No asegura ningn tipo de consistencia.

2.

No declara una interfaz de creacin de familias de productos que pueda ser redefinida por las clases derivadas.

El punto 2 quizs sea el ms fcil de ver, aunque el punto 1 puede generar dudas ... Por eso, discutiremos brevemente el problema y
lo demostraremos con un nuevo bloque de cdigo: al no tener una restriccin respecto a la interfaz de los creadores de familias, estos
pueden mezclarse, produciendo inconsistencias como las que se muestran en el bloque de cdigo:
/// <summary>
/// Simple Factory para Widgets de Windows
/// </summary>
public class WindowsCreator
{
public static IWindow CreateWindow()
{
return new WindowsWindow();
}
public static IScrollbar CreateScrollbar()
{
return new WindowsScrollbar();
}
}

/// <summary>
/// Simple Factory para Widgets de MAC
/// </summary>
public class MacCreator
{
public static IWindow CreateWindow()
{
return new MacWindow();

}
public static IScrollbar CreateScrollbar()
{
return new MacScrollbar();
}
}
/// <summary>
/// Ejemplo de Simple Factory
/// </summary>
public class ClienteDePruebaConError
{
public void Test()
{
IWindow window = CreadorWindows.CreateWindow();
IScrollbar scrollbar = CreadorMac.CreateScrollbar();
}
}
Cdigo 9 - Ejemplo de inconsistencias al utilizar Simple Factory para crear familias de productos.
En el ejemplo presentado en el Cdigo 9, se crean y combinan elementos de interfaz de usuario de diferentes familias. En el caso
concreto de nuestro ejemplo, estamos creando una ventana de Windows y una Scrollbar de Mac. Por lo tanto, estamos violando el
principio fundamental del patrn, que es proveer una interfaz consistente para la creacin de familias de productos relacionados. La
forma correcta de implementar este ejemplo utilizando el patrn Abstract Factory ha sido presentada previamente en el bloque de
Cdigo 6.
Principio de la pgina
5. Conclusin: Flexibilidad y Complejidad
Los patrones de fabricacin estudiados a lo largo de este artculo aaden flexibilidad a las aplicaciones, pero a expensas de mayor
complejidad. Por lo tanto, es recomendable analizar bien el problema a resolver antes de incluirlas.
Para terminar, considero oportuno citar la siguiente frase sobre las fbricas de Robert Martin [Martin05]:
No las use por defecto, y no comience utilizndolas frente al primer indicio de que puedan serle tiles ... Aguarde a tener un
problema concreto que las fbricas puedan resolver. Y en ese caso, no dude en utilizarlas.

Você também pode gostar