Patrón de Diseño Factory en Go: Creación y Uso Práctico

Clase 9 de 19Curso de Go Avanzado: Concurrencia y Patrones de Diseño

Resumen

¿Qué son los patrones de diseño y cómo nos ayudan?

Los patrones de diseño son soluciones comunes a problemas habituales en el desarrollo de software. Estos patrones facilitan la reutilización de código, mejoran la comprensión y fomentan buenas prácticas de programación. Hoy exploraremos el patrón de diseño Factory, un patrón creacional que permite crear fábricas de objetos flexibles y escalables.

¿Cómo implementar el patrón Factory en Go?

Para comenzar, crearemos una interfaz básica y las estructuras necesarias implementándolas en lenguaje Go. Veamos el proceso paso a paso:

  1. Crear la interfaz base: Primero, definimos una interfaz, llamada iProduct, que exigirá la implementación de varios métodos esenciales:

    type iProduct interface {
        setStock(stock int)
        getStock() int
        setName(name string)
        getName() string
    }
    
  2. Definir estructuras concretas: Ahora, definimos nuestra estructura Computer y sus métodos para cumplir con la interfaz iProduct.

    type Computer struct {
        name  string
        stock int
    }
    
    func (c *Computer) setStock(stock int) { c.stock = stock }
    func (c *Computer) getStock() int { return c.stock }
    func (c *Computer) setName(name string) { c.name = name }
    func (c *Computer) getName() string { return c.name }
    
  3. Composición sobre herencia: Creamos subclases como Laptop y Desktop, usando composición en Go en lugar de herencia.

    type Laptop struct {
        Computer
    }
    
    func newLaptop() iProduct {
        return &Laptop{Computer{name: "Laptop Computer", stock: 25}}
    }
    
    type Desktop struct {
        Computer
    }
    
    func newDesktop() iProduct {
        return &Desktop{Computer{name: "Desktop Computer", stock: 35}}
    }
    
  4. Implementar el Factory: El siguiente paso es crear la función getComputerFactory que utiliza el patrón Factory para devolver el producto adecuado.

    func getComputerFactory(computerType string) (iProduct, error) {
        if computerType == "laptop" {
            return newLaptop(), nil
        } else if computerType == "desktop" {
            return newDesktop(), nil
        }
        return nil, fmt.Errorf("Invalid computer type")
    }
    

¿Por qué usar el patrón Factory?

El patrón Factory nos ofrece múltiples beneficios:

  • Flexibilidad: Nos permite ampliar el número de productos a crear sin modificar el código existente.
  • Polimorfismo: Todas las instancias son tratadas como iProduct, promoviendo el uso del polimorfismo y la reutilización de código.
  • Mantenimiento: Centraliza y simplifica la gestión de instancias permitiendo modificaciones en un solo lugar.

¿Cómo probar y verificar la implementación?

Crear una función de impresión para visualizar los resultados y verificar el comportamiento polimorfo:

func printNameAndStock(p iProduct) {
    fmt.Printf("Product Name: %s, Stock: %d\n", p.getName(), p.getStock())
}

func main() {
    laptop, _ := getComputerFactory("laptop")
    desktop, _ := getComputerFactory("desktop")

    printNameAndStock(laptop)
    printNameAndStock(desktop)
}

Ejecutando este código comprobarás que las instancias de Laptop y Desktop son tratadas adecuadamente como instancias de iProduct.

¿Cuáles son los pros y contras del patrón Factory?

El uso del patrón Factory ofrece claridad en la creación de objetos y flexibilidad para añadir nuevos productos. Sin embargo, puede hacer que el código sea más complejo y difícil de leer, especialmente para novatos en programación.

Al enfrentar la complejidad inicial, el patrón Factory se convierte en una herramienta poderosa para arquitecturas de software robustas. ¡Continúa explorando más patrones de diseño para seguir perfeccionando tus habilidades!