Patrón Abstract Factory
Parte de la sección Programación Orientada a Objetos del Journey de GO de Coddy. Lección 88 de 107.
El patrón Abstract Factory amplía el patrón Factory al crear familias de objetos relacionados sin especificar sus tipos concretos. En lugar de una única función de fábrica, defines una interfaz de fábrica que varias fábricas concretas implementan, y cada una produce un conjunto coherente de objetos relacionados.
Considera un kit de herramientas de interfaz de usuario que necesita crear botones y casillas de verificación. Los distintos sistemas operativos requieren implementaciones diferentes, pero los componentes deben funcionar juntos de manera coherente:
type Button interface {
Render() string
}
type Checkbox interface {
Check() string
}
// Interfaz de fábrica abstracta
type GUIFactory interface {
CreateButton() Button
CreateCheckbox() Checkbox
}Cada fábrica concreta produce una familia de componentes relacionados:
// Familia Windows
type WindowsButton struct{}
func (w WindowsButton) Render() string { return "Windows Button" }
type WindowsCheckbox struct{}
func (w WindowsCheckbox) Check() string { return "Windows Checkbox" }
type WindowsFactory struct{}
func (w WindowsFactory) CreateButton() Button { return WindowsButton{} }
func (w WindowsFactory) CreateCheckbox() Checkbox { return WindowsCheckbox{} }
// Familia Mac
type MacButton struct{}
func (m MacButton) Render() string { return "Mac Button" }
type MacCheckbox struct{}
func (m MacCheckbox) Check() string { return "Mac Checkbox" }
type MacFactory struct{}
func (m MacFactory) CreateButton() Button { return MacButton{} }
func (m MacFactory) CreateCheckbox() Checkbox { return MacCheckbox{} }El código del cliente funciona con la interfaz de fábrica y permanece independiente de las implementaciones concretas:
func BuildUI(factory GUIFactory) {
button := factory.CreateButton()
checkbox := factory.CreateCheckbox()
fmt.Println(button.Render(), checkbox.Check())
}Usa Abstract Factory cuando tu sistema necesite trabajar con varias familias de productos relacionados y quieras garantizar que los componentes de la misma familia se utilicen juntos. Es más complejo que una Factory simple, así que recurre a él solo cuando realmente necesites gestionar familias de productos.
Desafío
Fácil¡Construyamos un sistema de tienda de muebles usando el patrón Abstract Factory! Crearás fábricas que producen familias de artículos de mobiliario relacionados: cada fábrica produce un estilo coherente (Modern o Vintage), lo que garantiza que las sillas y las mesas de la misma fábrica combinen estéticamente.
Organizarás tu código en tres archivos:
furniture.go: Define tus interfaces de producto y los tipos concretos de muebles.Crea dos interfaces de producto:
Chaircon un métodoSitOn() stringTablecon un métodoPlaceItems() string
Implementa dos familias de muebles:
- Familia Modern:
ModernChairdevuelveSitting on a sleek modern chairyModernTabledevuelvePlacing items on a glass modern table - Familia Vintage:
VintageChairdevuelveSitting on an ornate vintage chairyVintageTabledevuelvePlacing items on a wooden vintage table
factory.go: Define tu interfaz de fábrica abstracta y las fábricas concretas.Crea una interfaz
FurnitureFactorycon dos métodos:CreateChair() ChairCreateTable() Table
Implementa dos fábricas concretas:
ModernFactory, que produceModernChairyModernTableVintageFactory, que produceVintageChairyVintageTable
Crea también una función
GetFactory(style string) FurnitureFactoryque devuelva la fábrica adecuada según el estilo (modernovintage). UsaModernFactorypara los estilos no reconocidos.main.go: Usa tus fábricas para amueblar habitaciones.Crea una función
FurnishRoom(factory FurnitureFactory) stringque use la fábrica para crear una silla y una mesa, y luego devuelva una cadena formateada que muestre ambas acciones en líneas separadas.Lee una entrada de estilo, obtén la fábrica adecuada, amuebla una habitación e imprime el resultado.
Se proporcionarán las siguientes entradas:
- Línea 1: Estilo de los muebles (
modern,vintageo cualquier otra cosa)
Por ejemplo, dada la siguiente entrada:
modernTu salida debería ser:
Sitting on a sleek modern chair
Placing items on a glass modern tableY dada la siguiente entrada:
vintageTu salida debería ser:
Sitting on an ornate vintage chair
Placing items on a wooden vintage tableY dada la siguiente entrada:
rusticTu salida debería ser:
Sitting on a sleek modern chair
Placing items on a glass modern tableObserva cómo la función FurnishRoom funciona con cualquier fábrica mediante la interfaz. No sabe si está creando muebles modernos o vintage. ¡Esto garantiza que todos los muebles de una habitación provengan de la misma familia, manteniendo un estilo coherente!
Pruébalo tú mismo
package main
import "fmt"
// FurnishRoom usa una fábrica para crear muebles y devuelve el resultado
// TODO: Implementa esta función
// - Usa la fábrica para crear una silla y una mesa
// - Devuelve una cadena con el resultado de SitOn() en la primera línea y el resultado de PlaceItems() en la segunda línea
func FurnishRoom(factory FurnitureFactory) string {
// TODO: Crea silla y mesa usando la fábrica
// TODO: Devuelve una cadena formateada con ambas acciones en líneas separadas
return ""
}
func main() {
var style string
fmt.Scanln(&style)
// TODO: Obtén la fábrica apropiada según el estilo
// TODO: Amuebla una habitación usando la fábrica
// TODO: Imprime el resultado
}
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Programación Orientada a Objetos
1Fundamentos de POO en Go
Archivos externosEspacio de trabajo y módulos de GoPaquetes e importacionesNombres exportados vs. no exportadosIntroducción a la POO en GoStructs como clasesDefinición de métodos en structsReceptores de puntero vs. de valorInicialización de structsFunciones constructorasResumen - Calculadora simple4Interfaces
Introducción a las interfacesImplementación implícitaLa interfaz como contratoInterfaz vacía (any)Type AssertionType SwitchComposición de interfacesInterfaces Stringer y ErrorResumen: Calculadora de figuras7Encapsulamiento
Campos exportados vs. no exportadosEncapsulamiento a nivel de paqueteMétodos Getter y SetterOcultamiento de información en GoResumen - Registros de estudiantes10Genéricos (Go 1.18+)
Introducción a los GenéricosParámetros de tipoRestricciones de tipoStructs genéricosSolución alternativa para métodos genéricosResumen - Colección genérica13Patrones de diseño - Parte 1
Introducción a los patrones de diseñoPatrón SingletonPatrón FactoryPatrón Abstract FactoryPatrón ObserverPatrón Strategy2Inmersión profunda en Tipos y Structs
Tipos básicos y compuestosDefiniciones de tipos personalizadosEtiquetas de StructsStructs anónimosStructs anidadosValores cero y por defectoRepaso - Libreta de contactos5Composición sobre herencia
Por qué Go no tiene herenciaConceptos básicos de incrustación de structsPromoción de métodosIncrustación de múltiples structsIncrustación vs AgregaciónShadowing de métodos incrustadosResumen - Jerarquía de empleados8Manejo de Errores y OOP
La interfaz errorTipos de errores personalizadosEnvoltura de errores (fmt.Errorf)Errores centinelaerrors.Is() y errors.As()Panic, Defer y RecoverResumen - Analizador de archivos3Punteros y Memoria
Fundamentos de punteros en GoPunteros a StructsPaso por valor vs referenciaLa función new()Garbage Collection en GoResumen - Constructor de Linked List6Polimorfismo en Go
Polimorfismo mediante interfacesDuck Typing en GoReglas de satisfacción de interfacesColecciones polimórficasInyección de dependenciasResumen - Procesador de pagos9Concurrencia y POO
Fundamentos de GoroutinesChannels y comunicaciónChannels con buffer vs. sin bufferSentencia Selectsync.Mutex y sync.RWMutexsync.WaitGroupDiseño de estructuras Thread-SafeResumen - Worker PoolPractica por tu cuenta: Compilador de Go online