En este código inicial, se crean objetos manualmente usando condicionales anidados.
El código viola el Principio Abierto/Cerrado (OCP) y se vuelve difícil de mantener o escalar.
enum TransporteTipo {
Auto,
Barco,
Avion,
}
struct Auto;
struct Barco;
struct Avion;
impl Auto {
fn transportar(&self) {
println!("Transportando por carretera...");
}
}
impl Barco {
fn transportar(&self) {
println!("Transportando por mar...");
}
}
impl Avion {
fn transportar(&self) {
println!("Transportando por aire...");
}
}
fn crear_transporte(tipo: TransporteTipo) {
// Código espagueti: condicionales anidados, poca extensibilidad
if let TransporteTipo::Auto = tipo {
let a = Auto;
a.transportar();
} else if let TransporteTipo::Barco = tipo {
let b = Barco;
b.transportar();
} else if let TransporteTipo::Avion = tipo {
let c = Avion;
c.transportar();
} else {
println!("Tipo de transporte no soportado.");
}
}
fn main() {
crear_transporte(TransporteTipo::Auto);
crear_transporte(TransporteTipo::Barco);
crear_transporte(TransporteTipo::Avion);
}Cada vez que se agrega un nuevo tipo de transporte, hay que modificar la función crear_transporte.
No hay abstracción ni reutilización.
El código se vuelve difícil de mantener y rompe el principio OCP.
El comportamiento de creación y el de uso están mezclados.
Aplicamos el patrón Factory Method para encapsular la creación de los objetos en fábricas específicas. Esto mejora la extensibilidad y reduce el acoplamiento.
trait Transporte {
fn transportar(&self);
}
// Productos concretos
struct Auto;
struct Barco;
struct Avion;
impl Transporte for Auto {
fn transportar(&self) {
println!("Transportando por carretera...");
}
}
impl Transporte for Barco {
fn transportar(&self) {
println!("Transportando por mar...");
}
}
impl Transporte for Avion {
fn transportar(&self) {
println!("Transportando por aire...");
}
}
// Interfaz creadora (Factory)
trait TransporteFactory {
fn crear_transporte(&self) -> Box<dyn Transporte>;
}
// Fábricas concretas
struct AutoFactory;
struct BarcoFactory;
struct AvionFactory;
impl TransporteFactory for AutoFactory {
fn crear_transporte(&self) -> Box<dyn Transporte> {
Box::new(Auto)
}
}
impl TransporteFactory for BarcoFactory {
fn crear_transporte(&self) -> Box<dyn Transporte> {
Box::new(Barco)
}
}
impl TransporteFactory for AvionFactory {
fn crear_transporte(&self) -> Box<dyn Transporte> {
Box::new(Avion)
}
}
fn main() {
let auto_factory = AutoFactory;
let barco_factory = BarcoFactory;
let avion_factory = AvionFactory;
let transporte1 = auto_factory.crear_transporte();
transporte1.transportar();
let transporte2 = barco_factory.crear_transporte();
transporte2.transportar();
let transporte3 = avion_factory.crear_transporte();
transporte3.transportar();
}El Factory Method permite:
Encapsular la lógica de creación de objetos en una jerarquía de clases (o estructuras en Rust).
Cumplir con el Principio Abierto/Cerrado, ya que se pueden agregar nuevos tipos de transporte sin modificar el código existente.
Facilitar la extensibilidad y mantenibilidad del sistema.
Separar claramente la creación del uso de los objetos.
| Patrón | Cuándo usarlo | Diferencias clave |
|---|---|---|
| 🏭 Factory Method | Cuando se necesita delegar la creación de objetos a subclases o estructuras específicas. | Crea objetos de un mismo tipo general, pero deja que las subclases decidan cuál instanciar. |
| 🧱 Abstract Factory | Cuando se necesita crear familias completas de objetos relacionados o dependientes entre sí. | Gestiona múltiples productos a la vez (por ejemplo, Auto + Motor + Combustible), asegurando que sean compatibles. |
| 🏗️ Builder | Cuando un objeto debe construirse paso a paso o requiere múltiples configuraciones antes de usarse. | Se enfoca en la composición progresiva de un objeto complejo, no solo en su tipo. |
| 🧬 Prototype | Cuando la creación de objetos es costosa y conviene clonar instancias existentes. | Se basa en la duplicación de objetos ya existentes en lugar de su creación desde cero. |
| 📦 Singleton | Cuando solo debe existir una única instancia de una clase o estructura en todo el sistema. | Controla el acceso global a una instancia compartida, no la creación de múltiples objetos. |
El código espagueti inicial mezclaba creación y lógica, haciendo difícil su mantenimiento. El uso del Factory Method permite una estructura más limpia, extensible y mantenible, al delegar la creación a fábricas especializadas y respetar los principios SOLID.