El patrón de diseño Factory Method es un patrón creacional que se utiliza para crear objetos sin especificar la clase exacta de objeto que se creará. Este patrón es muy útil cuando se necesita crear objetos que pertenecen a una familia de objetos relacionados, pero se desconoce de antemano la clase exacta del objeto a crear.
En lugar de llamar directamente al constructor del objeto, el código llama a un método de fábrica que se encarga de crear y devolver la instancia del objeto. Esto permite la flexibilidad de cambiar las clases concretas de los objetos que se crean sin cambiar el código que utiliza los objetos.
Para implementar el patrón Factory Method, se requiere la creación de una interfaz o clase abstracta que declara el método de fábrica. Luego se crean las clases concretas que implementan esta interfaz o clase abstracta y proporcionan su propia implementación del método de fábrica para crear objetos. Finalmente, se utiliza el método de fábrica para crear los objetos.
Ejemplos
Un ejemplo concreto de este patrón en Java sería el uso de la interfaz AnimalFactory
y sus implementaciones concretas CatFactory
y DogFactory
. La interfaz AnimalFactory
declara el método de fábrica createAnimal()
, que es implementado por las clases CatFactory
y DogFactory
. Estas clases concretas se encargan de crear y devolver instancias de Cat
y Dog
, respectivamente.
public interface AnimalFactory {
Animal createAnimal();
}
public class CatFactory implements AnimalFactory {
public Animal createAnimal() {
return new Cat();
}
}
public class DogFactory implements AnimalFactory {
public Animal createAnimal() {
return new Dog();
}
}
En Python, se puede implementar el patrón Factory Method utilizando una clase abstracta y sus subclases concretas. Por ejemplo, se puede tener la clase abstracta Pizza
y sus subclases concretas CheesePizza
y PepperoniPizza
. La clase abstracta Pizza
declara el método de fábrica create_pizza()
, que es implementado por las subclases concretas.
from abc import ABC, abstractmethod
class Pizza(ABC):
@abstractmethod
def create_pizza(self):
pass
class CheesePizza(Pizza):
def create_pizza(self):
return "Cheese Pizza"
class PepperoniPizza(Pizza):
def create_pizza(self):
return "Pepperoni Pizza"
En Go, se puede implementar este patrón utilizando una interfaz y sus implementaciones concretas. Por ejemplo, se puede tener la interfaz ShapeFactory
y sus implementaciones concretas RectangleFactory
y CircleFactory
. La interfaz ShapeFactory
declara el método de fábrica CreateShape()
, que es implementado por las clases RectangleFactory
y CircleFactory
. Estas clases concretas se encargan de crear y devolver instancias de Rectangle
y Circle
, respectivamente.
type ShapeFactory interface {
CreateShape() Shape
}
type RectangleFactory struct {}
func (rf RectangleFactory) CreateShape() Shape {
return Rectangle{}
}
type CircleFactory struct {}
func (cf CircleFactory) CreateShape() Shape {
return Circle{}
}
En C#, se puede implementar el patrón Factory Method utilizando una interfaz y sus implementaciones, por ejemplo:
// Interfaz del producto
public interface IProduct
{
void DoSomething();
}
// Clase concreta del producto
public class ConcreteProductA : IProduct
{
public void DoSomething()
{
Console.WriteLine("Do something from ConcreteProductA");
}
}
// Otra clase concreta del producto
public class ConcreteProductB : IProduct
{
public void DoSomething()
{
Console.WriteLine("Do something from ConcreteProductB");
}
}
// Interfaz de la fábrica
public interface IFactory
{
IProduct CreateProduct();
}
// Implementación concreta de la fábrica que crea objetos de tipo ConcreteProductA
public class ConcreteFactoryA : IFactory
{
public IProduct CreateProduct()
{
return new ConcreteProductA();
}
}
// Implementación concreta de la fábrica que crea objetos de tipo ConcreteProductB
public class ConcreteFactoryB : IFactory
{
public IProduct CreateProduct()
{
return new ConcreteProductB();
}
}
// Uso de la fábrica
public class Client
{
private IFactory factory;
public Client(IFactory factory)
{
this.factory = factory;
}
public void DoSomethingWithProduct()
{
IProduct product = factory.CreateProduct();
product.DoSomething();
}
}
// Ejemplo de uso
public static void Main()
{
IFactory factoryA = new ConcreteFactoryA();
Client clientA = new Client(factoryA);
clientA.DoSomethingWithProduct(); // Salida: "Do something from ConcreteProductA"
IFactory factoryB = new ConcreteFactoryB();
Client clientB = new Client(factoryB);
clientB.DoSomethingWithProduct(); // Salida: "Do something from ConcreteProductB"
}
En este ejemplo, la interfaz IProduct
define el comportamiento de los productos que se pueden crear. Luego se definen dos clases concretas ConcreteProductA
y ConcreteProductB
que implementan esta interfaz y proporcionan su propia implementación del método DoSomething()
.
La interfaz IFactory define el método CreateProduct() que las fábricas deben implementar para crear instancias de IProduct
. Luego se definen dos implementaciones concretas de la fábrica ConcreteFactoryA
y ConcreteFactoryB
que crean objetos de tipo ConcreteProductA
y ConcreteProductB
, respectivamente.
Finalmente, la clase Client
utiliza una instancia de IFactory para crear instancias de IProduct
y llamar al método DoSomething()
. En el ejemplo, se crean dos instancias de Client
, cada una con una fábrica diferente, lo que les permite crear diferentes tipos de productos.
Conclusiones
El patrón de diseño Factory Method proporciona una forma flexible de crear objetos sin especificar la clase exacta de objeto que se creará. Esto permite que el código se adapte a diferentes tipos de objetos sin tener que modificar el código que utiliza los objetos.
Las ventajas de utilizar este patrón incluyen:
- Flexibilidad
- El patrón Factory Method permite que el código sea flexible y adaptable a diferentes tipos de objetos. Si se necesita cambiar la clase concreta de un objeto, simplemente se debe crear una nueva clase que implemente la interfaz o clase abstracta del producto y se modifica la fábrica para crear instancias de esta nueva clase.
- Mantenibilidad
- Al utilizar este patrón, el código es más mantenible y fácil de modificar. Si se necesita agregar un nuevo tipo de producto, solo se debe crear una nueva clase concreta y una nueva fábrica que pueda crear instancias de esta nueva clase.
- Separación de responsabilidades
- El patrón Factory Method separa la responsabilidad de crear objetos de la lógica del negocio. Esto permite que el código sea más modular y que cada clase se centre en su propia tarea específica.
- Reutilización de código
- Al utilizar este patrón, se puede reutilizar código existente para crear nuevas implementaciones de productos. Esto permite que el código sea más eficiente y que se evite la duplicación de código.
En resumen, el patrón de diseño Factory Method proporciona una forma flexible y mantenible de crear objetos en el código. Al utilizar este patrón, se puede separar la responsabilidad de crear objetos de la lógica del negocio, lo que permite que el código sea más modular y reutilizable.
Comentarios