Inicio
Tags

Publicado el

- 4 minutos de lectura

Dominando el Software: 8 Patrones de Diseño Esenciales para Programadores

img of Dominando el Software: 8 Patrones de Diseño Esenciales para Programadores

Los patrones de diseño son soluciones típicas a problemas comunes en el diseño de software. Aquí tienes ocho patrones de diseño esenciales que todo programador debería conocer, cada uno con una breve descripción y ejemplos prácticos para ilustrar cómo se pueden aplicar en situaciones reales de desarrollo.

1. Singleton

Propósito: Garantizar que una clase tenga solo una instancia y proporcionar un punto de acceso global a ella. Ejemplo: Usar un Singleton para manejar la conexión a una base de datos puede asegurar que las operaciones de lectura y escritura se realicen sobre la misma instancia de conexión, evitando conflictos y sobrecargas innecesarias.

   public class Database {
    private static Database instance;

    private Database() {}

    public static Database getInstance() {
        if (instance == null) {
            instance = new Database();
        }
        return instance;
    }
}

2. Observer

Propósito: Definir una dependencia uno-a-muchos entre objetos para que cuando uno cambie de estado, todos sus dependientes sean notificados automáticamente. Ejemplo: En una aplicación de comercio electrónico, un objeto Inventory puede notificar a Display y OrderManagement sistemas cuando un artículo es reabastecido.

   public class ProductInventory implements Subject {
    private List<Observer> observers = new ArrayList<>();
    private int stock;

    public void setStock(int stock) {
        this.stock = stock;
        notifyAllObservers();
    }

    public void attach(Observer observer) {
        observers.add(observer);
    }

    public void notifyAllObservers() {
        for (Observer observer : observers) {
            observer.update();
        }
    }
}

3. Factory Method

Propósito: Definir una interfaz para crear un objeto, pero dejar que las subclases decidan qué clase instanciar. Ejemplo: Un framework de UI puede proporcionar una interfaz Button, pero permitir que las subclases determinen si se crea un WindowsButton o un MacOSButton.

   public abstract class Dialog {
    public void renderWindow() {
        Button okButton = createButton();
        okButton.render();
    }

    public abstract Button createButton();
}

public class WindowsDialog extends Dialog {
    public Button createButton() {
        return new WindowsButton();
    }
}

4. Decorator

Propósito: Añadir dinámicamente responsabilidades adicionales a los objetos. Ejemplo: En una aplicación de dibujo, diferentes efectos como bordes o sombras pueden ser añadidos a una figura mediante Decorators.

   public interface Shape {
    void draw();
}

public class Circle implements Shape {
    public void draw() {
        System.out.println("Drawing a circle");
    }
}

public class RedBorderDecorator extends ShapeDecorator {
    public RedBorderDecorator(Shape decoratedShape) {
        super(decoratedShape);
    }

    public void draw() {
        decoratedShape.draw();
        setRedBorder(decoratedShape);
    }

    private void setRedBorder(Shape decoratedShape) {
        System.out.println("Border Color: Red");
    }
}

5. Strategy

Propósito: Permitir que el algoritmo varíe independientemente de los clientes que lo usan. Ejemplo: Un sistema de navegación puede cambiar el algoritmo de cálculo de ruta basado en el tipo de vehículo, condiciones del tráfico, o preferencias del usuario.

   public interface RouteStrategy {
    void buildRoute(String pointA, String pointB);
}

public class PublicTransportStrategy implements RouteStrategy {
    public void buildRoute(String pointA, String pointB) {
        System.out.println("Building public transport route");
    }
}

6. Adapter

Propósito: Convertir la interfaz de una clase en otra interfaz que los clientes esperan. Ejemplo: Un adaptador puede permitir que datos de sistemas de terceros se integren en una aplicación propia sin modificar el código que espera un formato específico.

   public interface Customer {
    String getName();
    String getEmail();
}

public class ExternalCustomer {
    private String name;
    private String contactEmail;

    public String getName() {
        return name;
    }

    public String getEmail() {
        return contactEmail;
    }
}

public class CustomerAdapter implements Customer {
    private ExternalCustomer externalCustomer;

    public CustomerAdapter(ExternalCustomer externalCustomer) {
        this.externalCustomer = externalCustomer;
    }

    public String getName() {
        return externalCustomer.getName();
    }

    public String getEmail() {
        return externalCustomer.getEmail();
    }


}

7. Command

Propósito: Encapsular una solicitud como un objeto, permitiendo así parametrizar clientes con diferentes solicitudes, hacer cola o llevar un registro de las solicitudes, y soportar operaciones deshacibles. Ejemplo: Una aplicación de edición de texto puede usar comandos para realizar y revertir ediciones, permitiendo así fácilmente implementar funcionalidad “deshacer”.

   public interface Command {
    void execute();
}

public class CopyCommand implements Command {
    private Document document;

    public CopyCommand(Document document) {
        this.document = document;
    }

    public void execute() {
        document.copy();
    }
}

8. Facade

Propósito: Proporcionar una interfaz unificada a un conjunto de interfaces en un subsistema. Facade define una interfaz de nivel más alto que hace el subsistema más fácil de usar. Ejemplo: Un sistema de home automation puede tener un facade que permite controlar luces, termostato, y sistema de seguridad con un solo método.

   public class HomeAutomationFacade {
    private Light light;
    private Thermostat thermostat;
    private SecuritySystem securitySystem;

    public HomeAutomationFacade(Light light, Thermostat thermostat, SecuritySystem securitySystem) {
        this.light = light;
        this.thermostat = thermostat;
        this.securitySystem = securitySystem;
    }

    public void awayMode() {
        light.turnOff();
        thermostat.setTemperature(18);
        securitySystem.activate();
    }
}

Estos patrones son herramientas poderosas en el arsenal de cualquier desarrollador, y su correcta aplicación puede resultar en software más robusto, flexible y mantenible.