Implementación Abstract Factory Pattern - lenoryv/Design-Patterns GitHub Wiki

Este ejemplo ilustra cómo puede utilizarse el patrón Abstract Factory para crear elementos de interfaz de usuario (UI) multiplataforma sin acoplar el código cliente a clases UI concretas, mientras se mantiene la consistencia de todos los elementos creados respecto al sistema operativo seleccionado.

Es de esperar que los mismos elementos UI de una aplicación multiplataforma se comporten de forma parecida, aunque tengan un aspecto un poco diferente en distintos sistemas operativos. Además, es nuestro trabajo que los elementos UI coincidan con el estilo del sistema operativo en cuestión. No queremos que nuestro programa represente controles de macOS al ejecutarse en Windows.

La interfaz fábrica abstracta declara un grupo de métodos que devuelven distintos productos abstractos. Estos productos se denominan familia y están relacionados por un tema o concepto de alto nivel. Normalmente, los productos de una familia pueden colaborar entre sí. Una familia de productos puede tener muchas variantes, pero los productos de una variante son incompatibles con los productos de otra.

interface GUIFactory is
    method createButton():Button
    method createCheckbox():Checkbox

Las fábricas concretas producen una familia de productos que pertenecen a una única variante. La fábrica garantiza que los productos resultantes sean compatibles. Las firmas de los métodos de las fábricas concretas devuelven un producto abstracto mientras que dentro del método se instancia un producto concreto.

class WinFactory implements GUIFactory is
    method createButton():Button is
        return new WinButton()
    method createCheckbox():Checkbox is
        return new WinCheckbox()

Cada fábrica concreta tiene una variante de producto correspondiente.

class MacFactory implements GUIFactory is
    method createButton():Button is
        return new MacButton()
    method createCheckbox():Checkbox is
        return new MacCheckbox()

Cada producto individual de una familia de productos debe tener una interfaz base. Todas las variantes del producto deben implementar esta interfaz.

interface Button is
    method paint()

Los productos concretos son creados por las fábricas concretas correspondientes.

class WinButton implements Button is
    method paint() is
        // Representa un botón en estilo Windows.

class MacButton implements Button is
    method paint() is
        // Representa un botón en estilo macOS.

Aquí está la interfaz base de otro producto. Todos los productos pueden interactuar entre sí, pero sólo entre productos de la misma variante concreta es posible una interacción adecuada.

interface Checkbox is
    method paint()

class WinCheckbox implements Checkbox is
    method paint() is
        // Representa una casilla en estilo Windows.

class MacCheckbox implements Checkbox is
    method paint() is
        // Representa una casilla en estilo macOS.

El código cliente funciona con fábricas y productos únicamente a través de tipos abstractos: GUIFactory, Button y Checkbox. Esto te permite pasar cualquier subclase fábrica o producto al código cliente sin descomponerlo.

class Application is
    private field factory: GUIFactory
    private field button: Button
    constructor Application(factory: GUIFactory) is
        this.factory = factory
    method createUI() is
        this.button = factory.createButton()
    method paint() is
        button.paint()

La aplicación elige el tipo de fábrica dependiendo de la configuración actual o de los ajustes del entorno y la crea durante el tiempo de ejecución (normalmente en la etapa de inicialización).

class ApplicationConfigurator is
    method main() is
        config = readApplicationConfigFile()

        if (config.OS == "Windows") then
            factory = new WinFactory()
        else if (config.OS == "Mac") then
            factory = new MacFactory()
        else
            throw new Exception("Error! Unknown operating system.")

        Application app = new Application(factory)