Está en la página 1de 16

Patrones de creación (I): Factory Patterns

8 Votes

Habíamos quedado en que los patrones creacionales o de creación eran aquellos en los que se
delegaba la instanciación de un objeto en otro en lugar de recurrir a un simple new(). La pregunta
que nos hacemos es: ¿por qué hacer esto? ¿Qué interés práctico puede existir en crear una clase
cuya función sea instanciar otras clases pudiendo dejarle el trabajo a la clase original?
Bien, esta forma de trabajar puede ser útil en algunos escenarios, pero el principal suele involucrar
el no saber qué objeto vamos a instanciar hasta el momento de la ejecución. Valiéndonos del
polimorfismo podremos utilizar una interfaz para alojar una referencia a un objeto que será
instanciado por un tercero en lugar de dejar que sea el propio constructor del objeto el que
proporcione la instancia. Hablando en plata, pasaremos de esto:

1MotorDiesel motor = new MotorDiesel();


A esto otro:
1 IMotor iMotor = MotorFactory.CreateInstance(tipoMotor);
Por tanto, nuestro objetivo principal será la encapsulación de la creación de objetos. Volveremos
al ejemplo que hemos usado en otras ocasiones: vehículos con un motor que está representado
mediante una interfaz que será implementada por las clases MotorDiesel y MotorGasolina. La
interfaz expondrá las siguientes propiedades y métodos:

1 namespace Patterns.Factory.SimpleFactory.Interfaces
2 {
3 public interface IMotor
4 {
5 public int Estabilidad { get; set; }
6 public decimal ParMotor { get; set; }
7 public int Potencia { get; set; }
8 public decimal Rendimiento { get; set; }
9 public int VelocidadNominal { get; set; }
10
11 string ConsumirCombustible();
12 string InyectarCombustible();
13 string RealizarEscape();
14 string RealizarExpansion();
15 }
16 }
A continuación codificaremos las dos clases que implementan la interfaz.
En primer lugar implementaremos el motor Diesel, cuyos métodos devolverán cadenas de texto con
sus respectivos mensajes. Además implementará un método privado RealizarCombustion() para
simbolizar el tratamiento del combustible.
public class MotorDiesel : IMotor
1 {
2 #region IMotor Members
3
4 int Estabilidad { get; set; }
5 decimal ParMotor { get; set; }
6 int Potencia { get; set; }
7 decimal Rendimiento { get; set; }
8 int VelocidadNominal { get; set; }
9
10 public string ConsumirCombustible()
11 {
12
return RealizarCombustion();
13
}
14
15
public string InyectarCombustible(int cantidad)
16
{
17
18 return string.Format("MotorDiesel: Inyectados {0} ml. de
19 Gasoil.", cantidad);
20 }
21
22 public string RealizarEscape()
23 {
24 return "MotorDiesel: Realizado escape de gases";
25 }
26
27 public string RealizarExpansion()
28 {
29 return "MotorDiesel: Realizada expansion";
30 }
31
32 #endregion
33
34 private string RealizarCombustion()
35 {
36 return "MotorDiesel: Realizada combustion del Gasoil";
37 }
}
Realizamos lo propio con el motor de gasolina, salvando el hecho que, en lugar de realizar una
combustión, realizará una explosión. Por lo tanto, el nombre del método privado será
RealizarExplosion():
public class MotorGasolina : IMotor
{
1
#region IMotor Members
2
3
4 public int Estabilidad { get; set; }
5 public decimal ParMotor { get; set; }
6 public int Potencia { get; set; }
7 public decimal Rendimiento { get; set; }
8 public int VelocidadNominal { get; set; }
9
10 public string ConsumirCombustible()
11 {
12 return RealizarExplosion();
13 }
14
15 public string InyectarCombustible(int cantidad)
16 {
17 return string.Format("MotorGasolina: Inyectados {0} ml.
18 de Gasolina.", cantidad);
19 }
20
21 public string RealizarEscape()
22 {
23 return "MotorGasolina: Realizado escape de gases";
24 }
25
26 public string RealizarExpansion()
27 {
28 return "MotorGasolina: Realizada expansion";
29 }
30
31 #endregion
32
33 private string RealizarExplosion()
34 {
35 return "MotorGasolina: Realizada explosion de la
36 Gasolina";
37 }
}
Finalmente, crearemos una clase MotorFactory que exhiba un método público
CreateInstance(nombreClase) para instanciar, por ejemplo, un motor Diesel.
public class MotorFactory
1 {
2 public IMotor CreateInstance(string tipoMotor)
3 {
4 IMotor resultado;
5
6
switch (tipoMotor)
7
{
8
case "MotorDiesel":
9
10 resultado = new MotorDiesel() { Estabilidad =
11 100, Potencia = 40, Rendimiento = 800, VelocidadNominal = 0 };
12 break;
default:
13
resultado = null;
14
break;
15
}
16
17
18 return resultado;
19 }
}
Lo que estamos haciendo aquí no es otra cosa que delegar en MotorFactory la tarea de instanciar el
motor. Ya tenemos el motor Diesel. Nos falta ahora el Gasolina. Para ello deberemos modificar la
clase MotorFactory y añadir un nuevo case a la sentencia switch:

1 public class MotorFactory


2 {
3 public IMotor CreateInstance(string tipoMotor)
4 {
5 IMotor resultado;
6
7 switch (tipoMotor)
8 {
9 case "MotorDiesel":
10 resultado = new MotorDiesel();
11 break;
12 case "MotorGasolina":
13 resultado = new MotorGasolina();
14 break;
15 default:
16 resultado = null;
17 break;
18 }
19
20 return resultado;
21 }
22 }
El diagrama de clases de esta primera factoría sería el siguiente:
Si quisiéramos obtener un motor diesel, por lo tanto, bastaría con el siguiente código:

1 static void Main(string[] args)


2 {
3 MotorFactory factory = new MotorFactory();
4
5 IMotor motorDiesel = factory.CreateInstance("MotorDiesel");
6
7 if (motorDiesel == null)
8 return;
9
10 Console.WriteLine(motorDiesel.InyectarCombustible(20));
11 Console.WriteLine(motorDiesel.ConsumirCombustible());
12 Console.WriteLine(motorDiesel.RealizarExpansion());
13 Console.WriteLine(motorDiesel.RealizarEscape());
14 Console.ReadLine();
15 }
La ejecución daría origen al siguiente resultado:

Principios SOLID
Lo que acabamos de hacer es delegar la decisión de instanciar un motor u otro hasta el momento en
el que la variable tipoMotor llega a nuestro método CreateInstance, lo cual flexibiliza el código
permitiendo que no nos atemos a un tipo de motor concreto en tiempo de compilación. Sin
embargo, al aparecer un nuevo tipo de motor hemos tenido que modificar una clase para incluir el
nuevo elemento a instanciar.
Si recordamos el artículo sobre la inyección de dependencias, comentamos por encima los
Principios
SOLID propuestos por Robert C. Martin, que eran los siguientes:
• Responsabilidad única: un objeto sólo debe tener una única responsabilidad.
• Abierto/cerrado: una clase debe estar abierta para su extensión, pero cerrada para su
modificación.
• Principio de sustitución de Liskov: una clase padre siempre debe poder ser sustituida por
una clase hija sin alterar el comportamiento del programa.
• Segregación de la Interfaz: es preferible contar con muchas interfaces específicas que con
una de propósito general.
• Inversión de dependencia: se debe depender de abstracciones, no de concreciones.
Si cada vez que aparezca un nuevo motor tenemos que modificar nuestra factoría para darle cabida
en nuestro proceso de instanciado, estaremos violando directamente el principio
abierto/cerrado, ya que las clases deben extenderse, no modificarse.
Por lo tanto, lo que estamos afirmando es que es necesario encontrar un modo de generalizar
nuestra factoría de tal modo que no sea necesario modificarla en el caso de que un nuevo tipo se
añada al ensamblado. El problema, a simple vista, parece irresoluble por métodos ajenos a la
brujería. Sin embargo, recordemos que la razón de ser de los patrones de diseño era precisamente
esta: proporcionar soluciones generales a problemas concretos. Y este problema concreto tiene
una solución más sencilla de lo que parece: bucear en las tripas del ensamblado y generar un listado
de pares clave-valor con los tipos que se ajusten a lo que necesitamos. Entraremos, por lo tanto, en
el campo de Reflection.

Reflection al rescate
Ya hemos usado Reflection en otras ocasiones, pero no le hemos dado un uso realmente práctico. Lo
hemos utilizado para extraer los métodos y propiedades de una clase, pero sin un motivo real por el
que deberíamos hacer eso. Aquí tenemos uno muy bueno.

Configurando la factoría mediante un fichero XML


Un primer acercamiento puede ser el siguiente: crear una sección en nuestro fichero de
configuración (o cualquier otro fichero XML, base de datos…) que contenga el nombre de las
clases que nuestra factoría puede generar. El constructor de la factoría iterará sobre estos elementos
y creará un diccionario con pares clave-valor cuya clave será el nombre del tipo indicado en el
fichero y cuyo valor correspondiente será el tipo en sí. Por tanto, añadiremos una nueva sección a
nuestro fichero app.config, del siguiente modo:
1 <?xml version="1.0" encoding="utf-8" ?>
2 <configuration>
3 <configSections>
4 <section name="AllowedMotorTypes"
type="System.Configuration.NameValueSectionHandler" />
</configSections>

5 <startup>
6 <supportedRuntime version="v4.0"
7 sku=".NETFramework,Version=v4.5" />
8 </startup>
9
10 <AllowedMotorTypes>
11 <add
12 key="Patterns.Factory.SimpleFactory.Motores.MotorDiesel"
13 value="true" />
14 <add
15 key="Patterns.Factory.SimpleFactory.Motores.MotorGasolina"
16 value="true" />
</AllowedMotorTypes>

</configuration>
A continuación añadiremos una referencia a la biblioteca System.Configuration, y haremos uso del
siguiente código para lograr nuestro objetivo: instanciaremos un objeto de la clase
NameValueCollection que simbolizará la sección que hemos creado, y usaremos una sentencia
LINQ para iterar sobre todas las claves de la sección. Sobre esta consulta usaremos el método de
extensión ToDictionary(campoClave, campoValor) en los que indicaremos el contenido de key para
la clave y, a través de Reflection, recuperaremos el tipo correspondiente a esa clave para
almacenarlo como valor.
1 private void ConfiguracionDesdeXml()
2 {
3 // Extraemos los pares clave-valor del fichero de
4 configuracion, concretamente de
5 // la seccion AllowedMotorTypes
6 NameValueCollection settings =
7 ConfigurationManager.GetSection("AllowedMotorTypes") as
8 NameValueCollection;
9
10 if (settings != null)
11 {
12 // Instanciamos el diccionario<nombreTipo, tipo>
13 tiposInstanciables = (from clave in
14 settings.AllKeys // Recorremos todas las claves
15 where
16 bool.Parse(settings[clave]) // ...en las que value sea
"true"
select clave).ToDictionary(key =>
key, // La clave del diccionario sera "key"
key =>
Assembly.GetExecutingAssembly().GetType(key)); // El valor sera
el tipo
}
}
Configurando la factoría mediante las clases del ensamblado
Una segunda posibilidad consiste en recorrer todas las clases existentes en el ensamblado,
comprobar si implementan la interfaz IMotor y, en caso afirmativo, añadirla a un diccionario en el
que se relacione el nombre de la clase con el tipo que representa. Una vez que se invoque el método
CreateInstance, se consultará el diccionario usando el parámetro del método como clave y se
instanciará el tipo asociado mediante la clase Activator.
Resumiendo, el proceso será el siguiente:
• Al instanciar la factoría, se recorren todas las clases del ensamblado.
• Por cada clase del ensamblado
• Si la clase implementa la interfaz que nuestra factoría se encarga de
instanciar, se añade al diccionario(nombreClase, tipo)
• Al invocar el método CreateInstance(nombreClase), se consulta el diccionario y se recupera
el tipo asociado, instanciándolo mediante Activator.
private void ConfiguracionAutomatica()
{
// Usamos LINQ para obtener un diccionario (nombreClase,
1 tipoClase) a partir de todos
2 // aquellos tipos del ensamblado actual que implementen la
3 interfaz IMotor.
4 tiposInstanciables = (from tipo in
5 Assembly.GetExecutingAssembly().GetTypes()
6 where
7 tipo.GetInterface(typeof(IMotor).ToString()) != null
8 select tipo).ToDictionary(t =>
9 t.ToString(), // Clave: nombre del tipo
10 t =>
t); // Valor: tipo

}
Como vemos, el proceso de recorrer el ensamblado no es más que una forma de configurar la
factoría. Este proceso no tiene por qué ser como el que aquí se expone: puede recorrerse un fichero
XML, una base de datos o cualquier otra forma de proporcionar a nuestra factoría un método de
saber qué clases puede instanciar.
El siguiente paso será obtener el tipo a partir de la cadena de texto que recibirá nuestro método
CreateInstance(). Esto será tan sencillo como consultar el diccionario y devolver el resultado.
private Type ObtenerTipo(string nombreTipo)
1{
2
if (tiposInstanciables == null)
3
return null;
4
else
5
6 return (tiposInstanciables.ContainsKey(nombreTipo) ?
tiposInstanciables[nombreTipo] : null);
7
}
Por último, codificaremos el método CreateInstance(), que obtendrá el tipo del diccionario a partir
de la cadena de texto e instanciará el objeto a partir de su tipo. Existen varias formas de realizar esta
operación. La primera de ellas será mediante el método Activator.CreateInstance(tipo). Esta
invocación equivale al constructor por defecto de la clase:
public IMotor CreateInstance(string tipoMotor)
1{
2 // Usamos Activator.CreateInstance(tipo) para instanciar el
3 objeto de forma dinamica
4 IMotor resultado =
5 (IMotor)Activator.CreateInstance(ObtenerTipo(tipoMotor));
6
7 return resultado;
}
Un segundo método sería a través del método
tipo.GetConstructor(arrayConTiposDeLosParámetros).Invoke(arrayConLosParámetros). En el
supuesto de que el constructor no posea parámetros (constructor por defecto), le pasaríamos el valor
Type.EmptyTypes a GetConstructor y null al método Invoke.
// Otra forma de instanciar el objeto podria haber sido
obteniendo el constructor por
1 // defecto e invocarlo mediante el metodo Invoke
2 IMotor resultado =
3 (IMotor)ObtenerTipo(tipoMotor).GetConstructor(Type.EmptyTypes).In
voke(null);
En caso de que el constructor que queremos invocar requiriese por ejemplo un valor entero, le
pasaríamos un array con un único elemento con el tipo entero a GetConstructor y un array con un
único elemento entero al método Invoke.
// Si tuviesemos un constructor del estilo a MotorFactory(int
dato), esta ultima invocacion
1 // equivaldria a "new MotorFactory(34)":
2 IMotor resultado =
3 (IMotor)ObtenerTipo(tipoMotor).GetConstructor(new[]
{typeof(int) }).Invoke(new object[] {34} );

Patrón Factory Method


Hasta ahora hemos explicado el concepto de factoría: una clase especializada en crear objetos. A
partir de aquí, podemos especializar aún más estas factorías para que generen tipos concretos. El
patrón Factory Method es similar a lo que hemos visto hasta ahora, con una pequeña variación: el
método CreateInstance() ya no generará una instancia, sino que o bien se convertirá en abstracto o
bien pertenecerá a una interfaz y dejará a las clases que la implementen la tarea de codificar su
comportamiento. Por lo tanto, nuestra clase MotorFactory ya no podrá utilizarse directamente para
generar objetos, sino que habrá que crear una nueva clase que herede de MotorFactory que
implemente el método CreateInstance() o bien transformar MotorFactory en una interfaz
IMotorFactory y dejar a las clases que la implementen el trabajo de instanciar las clases.
¿Qué conseguimos con esto? Básicamente, especializar las factorías. En lugar de tener una única
factoría que centralice todo el proceso de creación de objetos, tendremos varias clases factoría que
heredan de MotorFactory (o implementan IMotorFactory) que estarán especializadas en crear
variantes concretas.
En nuestro ejemplo sólo exponemos el caso de la instanciación de dos clases: MotorDiesel y
MotorGasolina. Además, las diferencias entre ambas clases son mínimas, por lo que una factoría
simple nos bastaría para nuestro diseño. Pero, ¿qué ocurriría si estas clases se especializaran cada
vez más y más? ¿Y si se añadiesen muchos más tipos de motores? Quizás la carga funcional sobre
nuestra factoría sería demasiada, por lo que sería aconsejable pasar al siguiente paso: utilizar
Factory Method para especializar las factorías.
Vamos a realizar, por lo tanto, el siguiente proceso:
1) Eliminar la clase MotorFactory y sustituirla por la interfaz IMotorFactory. Esta nueva interfaz
expondrá el método CreateInstance(), que deberá ser implementado por otras clases.

2) Crear dos nuevas clases, MotorDieselFactory y MotorGasolinaFactory, que implementen la


interfaz IMotorFactory y su método CreateInstance(), especializando el proceso de instanciado. El
nombre del patrón Factory Method viene precisamente de aquí.

Fijémonos en que el método CreateInstance sigue devolviendo una interfaz IMotor. Podríamos
pensar en que sería mejor que MotorGasolinaFactory.CreateInstance() devolviera una instancia de
MotorGasolina, ¿verdad? Bien, en realidad lo hará, pero recordemos que MotorGasolina
implementa la interfaz IMotor, por lo que puede usar esta referencia para devolver una instancia de
MotorGasolina tal y como lo ha venido haciendo hasta ahora. Dejemos el nivel de abstracción lo
más alto posible: la concreción no es buen amigo del diseñador.
Por tanto, el código de la interfaz IMotorFactory se simplificará hasta el punto de exponer
únicamente la firma del método CreateInstance():
1 public interface IMotorFactory
2{
3 IMotor CreateInstance();
4}
Configurando la factoría por defecto
Anteriormente vimos cómo podíamos configurar qué clases estaban disponibles para su instanciado:
mediante el recorrido de todas las clases del ensamblado que implementaban la interfaz IMotor o
mediante su inclusión en el fichero de configuración .config.
Sin embargo, en lugar de usar un fichero .config para estas tareas, es más aconsejable usar para ello
un fichero .settings. Este fichero consiste en una especie de diccionario al que se puede acceder
mediante la clase Settings (o Properties.Settings, dependiendo del Framework). Para añadir un
fichero de este tipo, agregaremos un nuevo elemento a nuestro proyecto de tipo Settings File.

A continuación, añadiremos un nuevo par clave-valor. El valor consistirá en el nombre de la clase


de la factoría que queremos utilizar. Por supuesto, podríamos utilizar varios pares clave-valor (en la
práctica es lo que se hace) dependiendo del contexto. Esto nos puede servir, entre otras cosas, para
instanciar distintos elementos dependiendo de si estamos desarrollando en producción, pruebas
unitarias, en desarrollo…

Hecho esto, creamos un método ObtenerFactoria() que devuelva una interfaz IMotorFactory que
alojará la instancia de la factoría concreta que queremos utilizar y que vendrá determinada por el
contenido del valor que hemos guardado en la configuración.
private static IMotorFactory ObtenerFactoria()
{
1 // Obtenemos el nombre de la clase de la configuracion
2 (Settings)
3 string nombreFactoria = Settings.Default.MotorFactory;
4
5 // Mediante Reflection, obtenemos el ensamblado e
6 instanciamos la factoria a
7 // partir del nombre de la clase (esto llamará a su
8 constructor por defecto)
9 Assembly ensamblado = Assembly.GetExecutingAssembly();
10 IMotorFactory factoria =
11 (IMotorFactory)ensamblado.CreateInstance(nombreFactoria);
12
13 // Devolvemos la instancia de la factoría
return factoria;
}
Codificando las factorías concretas
Lo siguiente será configurar el código de nuestras factorías individuales: MotorDieselFactory y
MotorGasolinaFactory. En estas clases se codificará el comportamiento del método
CreateInstance(), realizando las operaciones que consideremos oportunas para cada tipo de motor,
como asignarle valores a sus propiedades o realizar tareas fijas de inicialización. Por ejemplo:
1 public class MotorGasolinaFactory : IMotorFactory
2 {
3 #region IMotorFactory Members
4
5 public IMotor CreateInstance()
6 {
7 IMotor motorGasolina = new MotorGasolina()
8 {
9 Estabilidad = 100,
10 ParMotor = 40,
11 Potencia = 1200,
12 Rendimiento = 420,
13 VelocidadNominal = 47
14 };
15
16 return motorGasolina;
17 }
18
19 #endregion
20 }
21 public class MotorDieselFactory : IMotorFactory
22 {
23 #region IMotorFactory Members
24
25 public IMotor CreateInstance()
26 {
27 IMotor motorDiesel = new MotorDiesel()
28 {
29 Estabilidad = 60,
30 ParMotor = 90,
31 Potencia = 700,
32 Rendimiento = 220,
33 VelocidadNominal = 80
34 };
35
36 return motorDiesel;
37 }
38
39 #endregion
40 }
El diagrama de clases asociado a nuestro modelo tendría, por tanto, el siguiente aspecto:
Utilizando Factory Method
Finalmente, haremos uso de Factory Method mediante los siguientes pasos:
• Usamos una interfaz de la factoría (genérica) para alojar una instancia de la factoría
concreta, que será generada mediante el método ObtenerFactoria() accediendo a la
configuración para decidir qué factoría debe instanciar.
• Usamos una interfaz del motor (genérica) para alojar una instancia de un motor concreto,
que será generado mediante el método CreateInstance() de la factoría generada previamente.
• Hacemos uso de los métodos del objeto a través de su interfaz.
1 static void Main(string[] args)
2 {
3 // Usamos un método genérico para instanciar la factoría por
4 defecto.
5 // La factoría estará definida en la configuración
6 IMotorFactory factoria = ObtenerFactoria();
7
8 // Instanciamos un motor a través de la factoría.
9 // Fijémonos que únicamente tratamos con interfaces. En
10 ningún momento
11 // concretamos la clase con la que estamos trabajando
12 IMotor motor = factoria.CreateInstance();
13
14 // Finalmente, hacemos uso del motor a través de los métodos
15 de la
16 // interfaz IMotor.
17 Console.WriteLine(motor.InyectarCombustible(20));
18 Console.WriteLine(motor.ConsumirCombustible());
19 Console.WriteLine(motor.RealizarExpansion());
20 Console.WriteLine(motor.RealizarEscape());
Console.ReadLine();
}
Ejecutando nuestro código, vemos el resultado:

Patrón Abstract Factory (Factoría Abstracta)


La factoría abstracta va un paso más allá y extiende la funcionalidad de Factory Method mediante la
posibilidad de instanciar , en vez de un objeto, un conjunto de objetos relacionados o de la misma
familia. Hasta ahora disponíamos de un método CreateInstance() que generaba una instancia de un
motor. La factoría abstracta contendrá, en lugar de un único método, una colección de métodos que
al ser invocados instanciarán un objeto de una familia determinada. Este patrón suele ser corriente,
por ejemplo, en las conexiones a base de datos, donde una misma factoría es capaz de crear tanto
una conexión (DbConnection) como una órden Sql (SqlCommand) para distintas bases de datos. Por
ejemplo:
// Creamos la factoría concreta a través de un parámetro
DbProviderFactory factoryOracle =
1 DbProviderFactories.GetFactory("Oracle.DataAccess.Client");
2
3 // Instanciamos dos objetos distintos, pero de la misma familia
4 (Oracle)
5 DbConnection conexionOracle = factoryOracle.CreateConnection();
6 DbDataAdapter adapterOracle = factoryOracle.CreateDataAdapter();
7
8
9 // Creamos la factoría concreta a través de un parámetro
10 DbProviderFactory factorySql =
11 DbProviderFactories.GetFactory("System.Data.SqlClient");
12
13 // Instanciamos dos objetos distintos, pero de la misma familia
14 (SQL Server)
DbConnection conexionSql = factorySql.CreateConnection();
DbDataAdapter adapterSql = factorySql.CreateDataAdapter();
Como observamos, las interfaces DbConnection y DbDataAdapter efectúan las mismas operaciones
sobre una base de datos Oracle y SQL Server. Las factorías proporcionan estos elementos, junto a
algunos más. Por lo tanto, la diferencia fundamental entre Factory Method y Abstract Factory
radica en que el segundo patrón se centra en familias completas de objetos en lugar de hacerlo con
una única clase.
Usando este tipo de factorías es posible ampliar la funcionalidad de nuestras clases respetando el
Principio Abierto/Cerrado. El nombre de la clase de la nueva factoría (en el ejemplo anterior
Oracle.DataAccess.Client y System.Data.SqlClient) permitirá a la factoría abstracta instanciar
nuevas factorías a medida que las nuevas familias de objetos se vayan añadiendo.

¿Cuándo utilizar este patron? Ejemplos reales


Ya hemos visto un ejemplo real de factoría abstracta: la clase DbProviderFactory, que proporciona
factorías para diversas familias de bases de datos y permiten crear desde conexiones hasta
adaptadores de datos (DataAdapter).
Este patrón se utiliza también a la hora de definir elementos de interfaces gráficas, tales como
botones, paneles, etc. Dependiendo del motor gráfico que se vaya utilizar. Por ejemplo, se utilizaría
una factoría para elementos gráficos de Gtk, otra para elementos gráficos de KDE, otra para
elementos gráficos de xfce…
Si se cuenta con varios entornos (producción, desarrollo, pruebas) también puede ser útil para,
mediante el fichero de configuración, instanciar determinados objetos dependiendo de éste (por
ejemplo, para realizar el mocking de las pruebas unitarias).
Fuentes:
• http://www.dofactory.com/Patterns/PatternAbstract.aspx
• http://stackoverflow.com/questions/1673841/examples-of-gof-design-
patterns/2707195#2707195
• http://es.wikipedia.org/wiki/Abstract_Factory
• http://pluralsight.com/training/Courses/TableOfContents/patterns-library

También podría gustarte