Skip to content
IRC-CodingIRC-Coding
Design PatternsCreational PatternsSingleton FactoryBuilder PrototypeAbstract FactoryPatrones de Programación

Design Patterns Creacionales: Singleton, Factory, Builder

Patrones de diseño creacionales: Singleton, Factory, Builder, Prototype y Abstract Factory. Ejemplos prácticos en Java.

S

schutzgeist

16 min read
Design Patterns Creacionales: Singleton, Factory, Builder

Patrones de Diseño: Patrones Creacionales - Singleton, Factory, Builder, Prototype y Abstract Factory

Más artículos sobre Patrones de Diseño:

Este artículo es una guía completa de los Patrones de Diseño Creacionales, incluyendo Singleton, Factory, Builder, Prototype y Abstract Factory con ejemplos prácticos.

En Pocas Palabras

Los Patrones Creacionales abstraen la creación de objetos. Singleton garantiza una única instancia, Factory encapsula la lógica de creación, Builder permite construir objetos paso a paso, Prototype clona objetos y Abstract Factory crea familias de objetos relacionados.

Descripción Técnica Compacta

Los Patrones de Diseño Creacionales son patrones que controlan el proceso de instanciación de objetos y hacen este proceso más flexible.

Patrones Creacionales importantes:

Patrón Singleton

  • Propósito: Garantizar una única instancia
  • Aplicación: Loggers, configuración, thread pools
  • Implementación: Constructor privado, instancia estática
  • Thread-Safety: Sincronización o inicialización eager

Patrón Factory Method

  • Propósito: Delegar la creación de objetos a subclases
  • Aplicación: Frameworks, sistemas de plugins
  • Implementación: Método factory abstracto
  • Ventaja: Bajo acoplamiento, extensibilidad

Patrón Abstract Factory

  • Propósito: Crear familias de objetos relacionados
  • Aplicación: Toolkits de UI, drivers de base de datos
  • Implementación: Interfaz Factory con factories concretas
  • Ventaja: Familias de objetos consistentes

Patrón Builder

  • Propósito: Construir objetos complejos paso a paso
  • Aplicación: Objetos de configuración, DSLs
  • Implementación: Fluent Interface, clase Builder separada
  • Ventaja: Legibilidad, flexibilidad

Patrón Prototype

  • Propósito: Crear objetos mediante clonación
  • Aplicación: Creación optimizada para rendimiento
  • Implementación: Interfaz Cloneable, método clone()
  • Ventaja: Ahorro cuando la creación es costosa

Puntos Clave Relevantes para Exámenes

  • Patrones Creacionales: Patrones para instanciación flexible de objetos
  • Singleton: Una única instancia, puntos de acceso global
  • Factory Method: Creación de objetos delegada a subclases
  • Abstract Factory: Crear familias de objetos
  • Builder: Construcción paso a paso de objetos complejos
  • Prototype: Crear objetos mediante clonación
  • Relevancia IHK: Importante para arquitectura de software flexible

Componentes Clave

  1. Singleton: Instancia global con acceso controlado
  2. Factory Method: Creación de objetos abstraída
  3. Abstract Factory: Interfaz para familias de objetos
  4. Builder: Fluent Interface para construcción compleja
  5. Prototype: Creación de objetos basada en clonación
  6. Dependency Injection: Inversión de control
  7. Factory Configuration: Creación basada en configuración
  8. Object Pool: Reutilización de objetos

Ejemplos Prácticos

1. Patrón Singleton

// Inicialización Eager (Thread-Safe)
public class EagerSingleton {
    private static final EagerSingleton INSTANCE = new EagerSingleton();
    
    private EagerSingleton() {
        // Constructor privado evita instanciación
    }
    
    public static EagerSingleton getInstance() {
        return INSTANCE;
    }
    
    public void doSomething() {
        System.out.println("Eager Singleton funcionando");
    }
}

// Inicialización Lazy con Double-Checked Locking
public class LazySingleton {
    private static volatile LazySingleton instance;
    
    private LazySingleton() {
        // Constructor privado
    }
    
    public static LazySingleton getInstance() {
        if (instance == null) {
            synchronized (LazySingleton.class) {
                if (instance == null) {
                    instance = new LazySingleton();
                }
            }
        }
        return instance;
    }
    
    public void performAction() {
        System.out.println("Lazy Singleton en acción");
    }
}

// Singleton con Enum (Thread-Safe, Serialization-Safe)
public enum EnumSingleton {
    INSTANCE;
    
    public void doWork() {
        System.out.println("Enum Singleton funcionando");
    }
}

// Logger como Singleton
public class Logger {
    private static volatile Logger instance;
    private final List<String> logs = new ArrayList<>();
    
    private Logger() {}
    
    public static Logger getInstance() {
        if (instance == null) {
            synchronized (Logger.class) {
                if (instance == null) {
                    instance = new Logger();
                }
            }
        }
        return instance;
    }
    
    public void log(String message) {
        String timestamp = new Date().toString();
        String logEntry = "[" + timestamp + "] " + message;
        logs.add(logEntry);
        System.out.println(logEntry);
    }
    
    public List<String> getLogs() {
        return new ArrayList<>(logs);
    }
    
    public void clearLogs() {
        logs.clear();
    }
}

// Demo de Singleton
public class SingletonDemo {
    public static void main(String[] args) {
        System.out.println("=== Demo del Patrón Singleton ===");
        
        // Eager Singleton
        EagerSingleton eager1 = EagerSingleton.getInstance();
        EagerSingleton eager2 = EagerSingleton.getInstance();
        
        System.out.println("Eager Singleton - Misma instancia: " + (eager1 == eager2));
        eager1.doSomething();
        
        // Lazy Singleton
        LazySingleton lazy1 = LazySingleton.getInstance();
        LazySingleton lazy2 = LazySingleton.getInstance();
        
        System.out.println("Lazy Singleton - Misma instancia: " + (lazy1 == lazy2));
        lazy2.performAction();
        
        // Enum Singleton
        EnumSingleton enum1 = EnumSingleton.INSTANCE;
        EnumSingleton enum2 = EnumSingleton.INSTANCE;
        
        System.out.println("Enum Singleton - Misma instancia: " + (enum1 == enum2));
        enum1.doWork();
        
        // Logger Singleton
        Logger logger1 = Logger.getInstance();
        Logger logger2 = Logger.getInstance();
        
        System.out.println("Logger Singleton - Misma instancia: " + (logger1 == logger2));
        
        logger1.log("Aplicación iniciada");
        logger2.log("Usuario autenticado");
        
        System.out.println("Logs: " + logger1.getLogs());
    }
}

2. Patrón Factory Method

// Clase abstracta del producto
abstract class Vehiculo {
    protected String marca;
    protected String modelo;
    
    public Vehiculo(String marca, String modelo) {
        this.marca = marca;
        this.modelo = modelo;
    }
    
    public abstract void iniciar();
    public abstract void frenar();
    
    @Override
    public String toString() {
        return marca + " " + modelo;
    }
}

// Productos concretos
class Auto extends Vehiculo {
    public Auto(String marca, String modelo) {
        super(marca, modelo);
    }
    
    @Override
    public void iniciar() {
        System.out.println("Auto " + this + " iniciado");
    }
    
    @Override
    public void frenar() {
        System.out.println("Auto " + this + " frenado");
    }
}

class Motocicleta extends Vehiculo {
    public Motocicleta(String marca, String modelo) {
        super(marca, modelo);
    }
    
    @Override
    public void iniciar() {
        System.out.println("Motocicleta " + this + " iniciada");
    }
    
    @Override
    public void frenar() {
        System.out.println("Motocicleta " + this + " frenada");
    }
}

// Clase factory abstracta
abstract class FabricaVehiculo {
    // Factory Method
    public abstract Vehiculo crearVehiculo(String marca, String modelo);
    
    // Template Method
    public void producirYProbar(String marca, String modelo) {
        Vehiculo vehiculo = crearVehiculo(marca, modelo);
        System.out.println("Producido: " + vehiculo);
        
        // Prueba de calidad
        vehiculo.iniciar();
        vehiculo.frenar();
        System.out.println("Prueba superada");
    }
}

// Factories concretas
class FabricaAuto extends FabricaVehiculo {
    @Override
    public Vehiculo crearVehiculo(String marca, String modelo) {
        return new Auto(marca, modelo);
    }
}

class FabricaMotocicleta extends FabricaVehiculo {
    @Override
    public Vehiculo crearVehiculo(String marca, String modelo) {
        return new Motocicleta(marca, modelo);
    }
}

// Factory con parámetro
class FabricaVehiculoSimple {
    public static Vehiculo crearVehiculo(String tipo, String marca, String modelo) {
        switch (tipo.toLowerCase()) {
            case "auto":
                return new Auto(marca, modelo);
            case "motocicleta":
                return new Motocicleta(marca, modelo);
            default:
                throw new IllegalArgumentException("Tipo de vehículo desconocido: " + tipo);
        }
    }
}

// Demo Factory Method
public class FactoryMethodDemo {
    public static void main(String[] args) {
        System.out.println("=== Demo del Patrón Factory Method ===");
        
        // Factory Method Pattern
        FabricaVehiculo fabricaAuto = new FabricaAuto();
        FabricaVehiculo fabricaMotocicleta = new FabricaMotocicleta();
        
        System.out.println("--- Producción de Autos ---");
        fabricaAuto.producirYProbar("VW", "Golf");
        
        System.out.println("\n--- Producción de Motocicletas ---");
        fabricaMotocicleta.producirYProbar("BMW", "R1200");
        
        // Static Factory
        System.out.println("\n--- Static Factory ---");
        Vehiculo vwGolf = FabricaVehiculoSimple.crearVehiculo("auto", "VW", "Golf");
        Vehiculo bmwR1200 = FabricaVehiculoSimple.crearVehiculo("motocicleta", "BMW", "R1200");
        
        vwGolf.iniciar();
        bmwR1200.iniciar();
        
        // Factory con configuración
        System.out.println("\n--- Factory con Configuración ---");
        ConfiguradorVehiculo configurador = new ConfiguradorVehiculo();
        
        Vehiculo auto1 = configurador.crearVehiculo("auto", "Mercedes", "Clase C");
        Vehiculo motocicleta1 = configurador.crearVehiculo("motocicleta", "Harley", "Sportster");
        
        auto1.iniciar();
        motocicleta1.iniciar();
    }
}

// Factory con configuración
class ConfiguradorVehiculo {
    private Map<String, FabricaVehiculo> fabricas = new HashMap<>();
    
    public ConfiguradorVehiculo() {
        fabricas.put("auto", new FabricaAuto());
        fabricas.put("motocicleta", new FabricaMotocicleta());
    }
    
    public Vehiculo crearVehiculo(String tipo, String marca, String modelo) {
        FabricaVehiculo fabrica = fabricas.get(tipo.toLowerCase());
        if (fabrica == null) {
            throw new IllegalArgumentException("Tipo desconocido: " + tipo);
        }
        return fabrica.crearVehiculo(marca, modelo);
    }
    
    public void registrarFabrica(String tipo, FabricaVehiculo fabrica) {
        fabricas.put(tipo.toLowerCase(), fabrica);
    }
}

3. Patrón Abstract Factory

// Productos abstractos para tema UI
interface Button {
    void render();
    void onClick(Runnable action);
}

interface TextField {
    void render();
    void setText(String text);
    String getText();
}

interface Checkbox {
    void render();
    void setChecked(boolean checked);
    boolean isChecked();
}

// Productos concretos - Tema Windows
class WindowsButton implements Button {
    @Override
    public void render() {
        System.out.println("[Windows Button renderizado]");
    }
    
    @Override
    public void onClick(Runnable action) {
        System.out.println("Windows Button clickeado");
        action.run();
    }
}

class WindowsTextField implements TextField {
    private String text = "";
    
    @Override
    public void render() {
        System.out.println("[Windows TextField: '" + text + "']");
    }
    
    @Override
    public void setText(String text) {
        this.text = text;
    }
    
    @Override
    public String getText() {
        return text;
    }
}

class WindowsCheckbox implements Checkbox {
    private boolean checked = false;
    
    @Override
    public void render() {
        System.out.println("[Windows Checkbox: " + (checked ? "X" : " ") + "]");
    }
    
    @Override
    public void setChecked(boolean checked) {
        this.checked = checked;
    }
    
    @Override
    public boolean isChecked() {
        return checked;
    }
}

// Productos concretos - Tema macOS
class MacButton implements Button {
    @Override
    public void render() {
        System.out.println("[macOS Button renderizado]");
    }
    
    @Override
    public void onClick(Runnable action) {
        System.out.println("macOS Button clickeado");
        action.run();
    }
}

class MacTextField implements TextField {
    private String text = "";
    
    @Override
    public void render() {
        System.out.println("[macOS TextField: '" + text + "']");
    }
    
    @Override
    public void setText(String text) {
        this.text = text;
    }
    
    @Override
    public String getText() {
        return text;
    }
}

class MacCheckbox implements Checkbox {
    private boolean checked = false;
    
    @Override
    public void render() {
        System.out.println("[macOS Checkbox: " + (checked ? "✓" : " ") + "]");
    }
    
    @Override
    public void setChecked(boolean checked) {
        this.checked = checked;
    }
    
    @Override
    public boolean isChecked() {
        return checked;
    }
}

// Factory abstracta
interface GUIFactory {
    Button createButton();
    TextField createTextField();
    Checkbox createCheckbox();
}

// Factories concretas
class WindowsFactory implements GUIFactory {
    @Override
    public Button createButton() {
        return new WindowsButton();
    }
    
    @Override
    public TextField createTextField() {
        return new WindowsTextField();
    }
    
    @Override
    public Checkbox createCheckbox() {
        return new WindowsCheckbox();
    }
}

class MacFactory implements GUIFactory {
    @Override
    public Button createButton() {
        return new MacButton();
    }
    
    @Override
    public TextField createTextField() {
        return new MacTextField();
    }
    
    @Override
    public Checkbox createCheckbox() {
        return new MacCheckbox();
    }
}

// Código cliente
class Aplicacion {
    private Button button;
    private TextField textField;
    private Checkbox checkbox;
    
    public Aplicacion(GUIFactory factory) {
        button = factory.createButton();
        textField = factory.createTextField();
        checkbox = factory.createCheckbox();
    }
    
    public void crearUI() {
        System.out.println("=== UI siendo creada ===");
        
        button.render();
        textField.render();
        checkbox.render();
        
        // Añadir funcionalidad
        button.onClick(() -> {
            String text = textField.getText();
            System.out.println("Button clickeado con texto: " + text);
            checkbox.setChecked(!checkbox.isChecked());
            checkbox.render();
        });
        
        textField.setText("Texto de ejemplo");
        textField.render();
    }
}

// Demo de Abstract Factory
public class AbstractFactoryDemo {
    public static void main(String[] args) {
        System.out.println("=== Abstract Factory Pattern Demo ===");
        
        // Aplicación Windows
        System.out.println("\n--- Aplicación Windows ---");
        GUIFactory windowsFactory = new WindowsFactory();
        Aplicacion windowsApp = new Aplicacion(windowsFactory);
        windowsApp.crearUI();
        
        // Aplicación macOS
        System.out.println("\n--- Aplicación macOS ---");
        GUIFactory macFactory = new MacFactory();
        Aplicacion macApp = new Aplicacion(macFactory);
        macApp.crearUI();
        
        // Factory basada en sistema operativo
        System.out.println("\n--- Factory dinámica ---");
        String os = System.getProperty("os.name").toLowerCase();
        GUIFactory factory;
        
        if (os.contains("mac")) {
            factory = new MacFactory();
        } else {
            factory = new WindowsFactory();
        }
        
        Aplicacion appDinamica = new Aplicacion(factory);
        appDinamica.crearUI();
    }
}

4. Patrón Builder

// Producto complejo
class Computer {
    private final String cpu;
    private final String gpu;
    private final int ram;
    private final int storage;
    private final boolean hasWifi;
    private final boolean hasBluetooth;
    private final String operatingSystem;
    
    // Constructor privado
    private Computer(Builder builder) {
        this.cpu = builder.cpu;
        this.gpu = builder.gpu;
        this.ram = builder.ram;
        this.storage = builder.storage;
        this.hasWifi = builder.hasWifi;
        this.hasBluetooth = builder.hasBluetooth;
        this.operatingSystem = builder.operatingSystem;
    }
    
    // Getters
    public String getCpu() { return cpu; }
    public String getGpu() { return gpu; }
    public int getRam() { return ram; }
    public int getStorage() { return storage; }
    public boolean hasWifi() { return hasWifi; }
    public boolean hasBluetooth() { return hasBluetooth; }
    public String getOperatingSystem() { return operatingSystem; }
    
    @Override
    public String toString() {
        return "Computer{" +
                "cpu='" + cpu + '\'' +
                ", gpu='" + gpu + '\'' +
                ", ram=" + ram + "GB" +
                ", storage=" + storage + "GB" +
                ", hasWifi=" + hasWifi +
                ", hasBluetooth=" + hasBluetooth +
                ", operatingSystem='" + operatingSystem + '\'' +
                '}';
    }
    
    // Clase Builder
    public static class Builder {
        // Parámetros requeridos
        private final String cpu;
        private final String gpu;
        
        // Parámetros opcionales con valores por defecto
        private int ram = 8;
        private int storage = 256;
        private boolean hasWifi = true;
        private boolean hasBluetooth = false;
        private String operatingSystem = "Windows";
        
        // Constructor para parámetros requeridos
        public Builder(String cpu, String gpu) {
            this.cpu = cpu;
            this.gpu = gpu;
        }
        
        // Interfaz fluida para parámetros opcionales
        public Builder ram(int ram) {
            this.ram = ram;
            return this;
        }
        
        public Builder storage(int storage) {
            this.storage = storage;
            return this;
        }
        
        public Builder wifi(boolean hasWifi) {
            this.hasWifi = hasWifi;
            return this;
        }
        
        public Builder bluetooth(boolean hasBluetooth) {
            this.hasBluetooth = hasBluetooth;
            return this;
        }
        
        public Builder operatingSystem(String operatingSystem) {
            this.operatingSystem = operatingSystem;
            return this;
        }
        
        // Método build
        public Computer build() {
            // Validación
            if (ram < 4) {
                throw new IllegalArgumentException("RAM debe ser al menos 4GB");
            }
            if (storage < 128) {
                throw new IllegalArgumentException("Storage debe ser al menos 128GB");
            }
            
            return new Computer(this);
        }
    }
}

// Builder para objetos de configuración
class Configuracion {
    private final Map<String, String> propiedades;
    private final List<String> modulosActivos;
    private final String conexionBaseDatos;
    private final int timeout;
    
    private Configuracion(Builder builder) {
        this.propiedades = new HashMap<>(builder.propiedades);
        this.modulosActivos = new ArrayList<>(builder.modulosActivos);
        this.conexionBaseDatos = builder.conexionBaseDatos;
        this.timeout = builder.timeout;
    }
    
    public static class Builder {
        private Map<String, String> propiedades = new HashMap<>();
        private List<String> modulosActivos = new ArrayList<>();
        private String conexionBaseDatos = "localhost:5432";
        private int timeout = 30;
        
        public Builder propiedad(String clave, String valor) {
            propiedades.put(clave, valor);
            return this;
        }
        
        public Builder modulo(String modulo) {
            modulosActivos.add(modulo);
            return this;
        }
        
        public Builder conexionBaseDatos(String conexion) {
            this.conexionBaseDatos = conexion;
            return this;
        }
        
        public Builder timeout(int segundos) {
            this.timeout = segundos;
            return this;
        }
        
        public Configuracion build() {
            return new Configuracion(this);
        }
    }
    
    // Getters y toString
    public Map<String, String> getPropiedades() { return new HashMap<>(propiedades); }
    public List<String> getModulosActivos() { return new ArrayList<>(modulosActivos); }
    public String getConexionBaseDatos() { return conexionBaseDatos; }
    public int getTimeout() { return timeout; }
    
    @Override
    public String toString() {
        return "Configuracion{" +
                "propiedades=" + propiedades +
                ", modulosActivos=" + modulosActivos +
                ", conexionBaseDatos='" + conexionBaseDatos + '\'' +
                ", timeout=" + timeout +
                '}';
    }
}

// Demo de Builder Pattern
public class BuilderDemo {
    public static void main(String[] args) {
        System.out.println("=== Builder Pattern Demo ===");
        
        // PC gaming simple con Builder
        Computer gamingPC = new Computer.Builder("Intel i9", "NVIDIA RTX 3080")
            .ram(32)
            .storage(1000)
            .wifi(true)
            .bluetooth(true)
            .operatingSystem("Windows 11")
            .build();
        
        System.out.println("Gaming PC: " + gamingPC);
        
        // PC de oficina minimal
        Computer officePC = new Computer.Builder("Intel i5", "Intel HD Graphics")
            .build();
        
        System.out.println("Office PC: " + officePC);
        
        // Configuración con Builder
        Configuracion config = new Configuracion.Builder()
            .propiedad("app.name", "MyApp")
            .propiedad("app.version", "1.0.0")
            .modulo("authentication")
            .modulo("logging")
            .modulo("database")
            .conexionBaseDatos("prod.db.server.com:5432")
            .timeout(60)
            .build();
        
        System.out.println("\nConfiguración: " + config);
        
        // Builder anidado
        System.out.println("\n--- Builder Anidado ---");
        Computer server = new Computer.Builder("AMD EPYC", "AMD Radeon VII")
            .ram(128)
            .storage(4000)
            .wifi(false)
            .operatingSystem("Ubuntu Server")
            .build();
        
        System.out.println("Server: " + server);
        
        // Builder con validación
        try {
            Computer invalidPC = new Computer.Builder("Intel i3", "Intel HD")
                .ram(2)  // Inválido
                .build();
        } catch (IllegalArgumentException e) {
            System.out.println("Error de validación: " + e.getMessage());
        }
    }
}

5. Patrón Prototype

// Interfaz Prototype
interface Prototype<T> {
    T clone();
}

// Prototipos concretos
class Dokument implements Prototype<Dokument> {
    private String titel;
    private String inhalt;
    private List<String> tags;
    private Date erstellDatum;
    
    public Dokument(String titel, String inhalt) {
        this.titel = titel;
        this.inhalt = inhalt;
        this.tags = new ArrayList<>();
        this.erstellDatum = new Date();
    }
    
    // Copy Constructor
    private Dokument(Dokument original) {
        this.titel = original.titel;
        this.inhalt = original.inhalt;
        this.tags = new ArrayList<>(original.tags);
        this.erstellDatum = new Date(original.erstellDatum.getTime());
    }
    
    @Override
    public Dokument clone() {
        return new Dokument(this);
    }
    
    // Getters y setters
    public String getTitel() { return titel; }
    public void setTitel(String titel) { this.titel = titel; }
    
    public String getInhalt() { return inhalt; }
    public void setInhalt(String inhalt) { this.inhalt = inhalt; }
    
    public void addTag(String tag) { tags.add(tag); }
    public List<String> getTags() { return new ArrayList<>(tags); }
    
    @Override
    public String toString() {
        return "Dokument{" +
                "titel='" + titel + '\'' +
                ", inhalt='" + inhalt + '\'' +
                ", tags=" + tags +
                ", erstellDatum=" + erstellDatum +
                '}';
    }
}

// Objeto gráfico como prototipo
class GrafikObjekt implements Prototype<GrafikObjekt> {
    private String typ;
    private int x, y;
    private int breite, hoehe;
    private String farbe;
    private List<GrafikObjekt> kinder;
    
    public GrafikObjekt(String typ, int x, int y, int breite, int hoehe, String farbe) {
        this.typ = typ;
        this.x = x;
        this.y = y;
        this.breite = breite;
        this.hoehe = hoehe;
        this.farbe = farbe;
        this.kinder = new ArrayList<>();
    }
    
    // Deep clone con copy constructor
    private GrafikObjekt(GrafikObjekt original) {
        this.typ = original.typ;
        this.x = original.x;
        this.y = original.y;
        this.breite = original.breite;
        this.hoehe = original.hoehe;
        this.farbe = original.farbe;
        this.kinder = new ArrayList<>();
        
        // Deep clone para los hijos
        for (GrafikObjekt kind : original.kinder) {
            this.kinder.add(kind.clone());
        }
    }
    
    @Override
    public GrafikObjekt clone() {
        return new GrafikObjekt(this);
    }
    
    public void addKind(GrafikObjekt kind) {
        kinder.add(kind);
    }
    
    public void verschieben(int deltaX, int deltaY) {
        this.x += deltaX;
        this.y += deltaY;
        // Los hijos también se desplazan
        for (GrafikObjekt kind : kinder) {
            kind.verschieben(deltaX, deltaY);
        }
    }
    
    @Override
    public String toString() {
        return "GrafikObjekt{" +
                "typ='" + typ + '\'' +
                ", x=" + x + ", y=" + y +
                ", groesse=" + breite + "x" + hoehe +
                ", farbe='" + farbe + '\'' +
                ", kinder=" + kinder.size() +
                '}';
    }
}

// Registro de prototipos
class PrototypeRegistry {
    private Map<String, Prototype<?>> prototypen = new HashMap<>();
    
    public void registrierePrototyp(String key, Prototype<?> prototyp) {
        prototypen.put(key, prototyp);
    }
    
    @SuppressWarnings("unchecked")
    public <T extends Prototype<T>> T klonePrototyp(String key) {
        Prototype<?> prototyp = prototypen.get(key);
        if (prototyp == null) {
            throw new IllegalArgumentException("Prototyp nicht gefunden: " + key);
        }
        return (T) prototyp.clone();
    }
    
    public Collection<String> getVerfuegbarePrototypen() {
        return prototypen.keySet();
    }
}

// Gestor de prototipos para optimización de rendimiento
class PerformancePrototypManager {
    private Map<Class<?>, Prototype<?>> cache = new HashMap<>();
    
    @SuppressWarnings("unchecked")
    public <T extends Prototype<T>> T getOptimiertesClone(Class<T> klasse, T prototyp) {
        if (!cache.containsKey(klasse)) {
            cache.put(klasse, prototyp);
        }
        
        T cached = (T) cache.get(klasse);
        return cached.clone();
    }
    
    public void clearCache() {
        cache.clear();
    }
    
    public int getCacheSize() {
        return cache.size();
    }
}

// Demo del patrón Prototype
public class PrototypeDemo {
    public static void main(String[] args) {
        System.out.println("=== Prototype Pattern Demo ===");
        
        // Clonación simple
        System.out.println("\n--- Clonación simple ---");
        Dokument original = new Dokument("Bericht", "Dies ist ein Testbericht");
        original.addTag("wichtig");
        original.addTag("intern");
        
        System.out.println("Original: " + original);
        
        Dokument kopie = original.clone();
        kopie.setTitel("Bericht - Kopie");
        kopie.addTag("kopie");
        
        System.out.println("Kopie: " + kopie);
        System.out.println("Original nach Kopie: " + original);
        
        // Deep clone con objetos complejos
        System.out.println("\n--- Deep clone ---");
        GrafikObjekt container = new GrafikObjekt("Container", 0, 0, 800, 600, "weiß");
        
        GrafikObjekt button1 = new GrafikObjekt("Button", 10, 10, 100, 30, "blau");
        GrafikObjekt button2 = new GrafikObjekt("Button", 120, 10, 100, 30, "grün");
        
        container.addKind(button1);
        container.addKind(button2);
        
        System.out.println("Original Container: " + container);
        
        GrafikObjekt geklonteContainer = container.clone();
        geklonteContainer.verschieben(50, 50);
        
        System.out.println("Geklonter Container: " + geklonteContainer);
        System.out.println("Original nach Verschiebung: " + container);
        
        // Registro de prototipos
        System.out.println("\n--- Registro de prototipos ---");
        PrototypeRegistry registry = new PrototypeRegistry();
        
        // Registrar prototipos
        registry.registrierePrototyp("bericht", new Dokument("Standard-Bericht", ""));
        registry.registrierePrototyp("button", new GrafikObjekt("Button", 0, 0, 80, 25, "grau"));
        
        // Clonar prototipos desde el registro
        Dokument neuerBericht = registry.klonePrototyp("bericht");
        neuerBericht.setTitel("Monatsbericht");
        neuerBericht.setInhalt("Monatliche Statistiken...");
        
        GrafikObjekt neuerButton = registry.klonePrototyp("button");
        neuerButton.verschieben(200, 100);
        
        System.out.println("Neuer Bericht: " + neuerBericht);
        System.out.println("Neuer Button: " + neuerButton);
        
        System.out.println("Verfügbare Prototypen: " + registry.getVerfuegbarePrototypen());
        
        // Optimización de rendimiento
        System.out.println("\n--- Optimización de rendimiento ---");
        PerformancePrototypManager manager = new PerformancePrototypManager();
        
        Dokument template = new Dokument("Template", "Vorlageninhalt");
        
        // Muchos clones con optimización
        long startZeit = System.currentTimeMillis();
        for (int i = 0; i < 1000; i++) {
            Dokument schnell = manager.getOptimiertesClone(Dokument.class, template);
            schnell.setTitel("Dokument " + i);
        }
        long endZeit = System.currentTimeMillis();
        
        System.out.println("1000 optimierte Klone: " + (endZeit - startZeit) + "ms");
        System.out.println("Cache Größe: " + manager.getCacheSize());
    }
}

Resumen de Patrones Creacionales

PatrónPropósitoCuándo usarVentajas
SingletonGarantizar una única instanciaLogger, configuraciónAcceso global, eficiencia de memoria
Factory MethodDelegar la creación de objetosFrameworks, pluginsBajo acoplamiento, extensibilidad
Abstract FactoryCrear familias de objetosToolkits UI, bases de datosObjetos consistentes
BuilderConstruir objetos complejos paso a pasoConfiguración, DSLsLegibilidad, flexibilidad
PrototypeCrear objetos mediante clonaciónRendimiento, plantillasEficiencia de costos

Listas de Verificación para Implementación

Singleton

  • Constructor privado
  • Instancia estática
  • Thread-Safety
  • Serialization-Safety
  • Protección contra clonación

Factory Method

  • Método factory abstracto
  • Implementaciones concretas
  • Jerarquía de productos
  • Bajo acoplamiento

Abstract Factory

  • Interfaz Factory
  • Factories concretas
  • Familias de productos
  • Consistencia

Builder

  • Fluent Interface
  • Producto inmutable
  • Validación
  • Separación de requeridos y opcionales

Prototype

  • Interfaz Cloneable
  • Deep Clone
  • Registro de prototipos
  • Optimización de rendimiento

Ventajas e Inconvenientes

Ventajas de los Patrones Creacionales

  • Flexibilidad: Adaptar fácilmente la creación de objetos
  • Reutilización: Lógica de creación reutilizable
  • Encapsulación: Ocultar lógica compleja
  • Testabilidad: Facilitar mocking
  • Mantenibilidad: Creación centralizada

Inconvenientes

  • Complejidad: Clases e interfaces adicionales
  • Overhead: Más código en casos simples
  • Curva de aprendizaje: Entender los patrones requiere estudio
  • Sobre-ingeniería: Riesgo de soluciones demasiado complejas

Preguntas Frecuentes en Exámenes

  1. ¿Cuándo usar Singleton en lugar de una clase estática? Singleton para características OO como herencia, interfaces e inicialización perezosa.

  2. ¿Cuál es la diferencia entre Factory Method y Abstract Factory? Factory Method crea un producto, Abstract Factory crea familias de productos.

  3. Explica la ventaja del patrón Builder. Construcción paso a paso de objetos complejos con Fluent Interface y validación.

  4. ¿Cuándo es útil el patrón Prototype? Cuando la creación de objetos es costosa o necesitas muchos objetos similares.

Fuentes Principales

  1. https://refactoring.guru/design-patterns/creational-patterns
  2. https://www.oracle.com/technetwork/java/designpatterns-138485.html
  3. https://en.wikipedia.org/wiki/Creational_pattern

Lecturas Recomendadas: Design Patterns

Keine Bücher für Kategorie "design-patterns" gefunden.

Volver al blog
Share:

Nächster Artikel in Arquitectura de Software

Weiterlesen
Diagramas UML: Clases, Secuencia y Casos de Uso

Entradas relacionadas