Els patrons de disseny són solucions provades i documentades per a problemes comuns en el desenvolupament de programari. Aquests patrons ajuden a millorar la reutilització del codi, la flexibilitat i la mantenibilitat de les aplicacions. En aquest tema, explorarem alguns dels patrons de disseny més utilitzats en Java.

Contingut

Introducció als Patrons de Disseny

Els patrons de disseny es classifiquen en tres categories principals:

  • Patrons Creacionals: Ajuden a crear objectes de manera que es pugui separar el codi de creació de l'ús dels objectes.
  • Patrons Estructurals: Ajuden a compondre objectes i classes en estructures més grans mantenint la flexibilitat i eficiència.
  • Patrons de Comportament: Ajuden a definir com els objectes interactuen i es comuniquen entre ells.

Patrons Creacionals

Singleton

El patró Singleton assegura que una classe només tingui una instància i proporciona un punt d'accés global a aquesta instància.

public class Singleton {
    private static Singleton instance;

    private Singleton() {
        // Constructor privat per evitar la creació d'instàncies externes
    }

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

Factory Method

El patró Factory Method defineix una interfície per crear objectes, però permet a les subclasses decidir quin tipus d'objecte crear.

public abstract class Product {
    public abstract void use();
}

public class ConcreteProductA extends Product {
    @Override
    public void use() {
        System.out.println("Using Product A");
    }
}

public class ConcreteProductB extends Product {
    @Override
    public void use() {
        System.out.println("Using Product B");
    }
}

public abstract class Creator {
    public abstract Product factoryMethod();

    public void someOperation() {
        Product product = factoryMethod();
        product.use();
    }
}

public class ConcreteCreatorA extends Creator {
    @Override
    public Product factoryMethod() {
        return new ConcreteProductA();
    }
}

public class ConcreteCreatorB extends Creator {
    @Override
    public Product factoryMethod() {
        return new ConcreteProductB();
    }
}

Abstract Factory

El patró Abstract Factory proporciona una interfície per crear famílies d'objectes relacionats o dependents sense especificar les seves classes concretes.

public interface GUIFactory {
    Button createButton();
    Checkbox createCheckbox();
}

public class WinFactory implements GUIFactory {
    @Override
    public Button createButton() {
        return new WinButton();
    }

    @Override
    public Checkbox createCheckbox() {
        return new WinCheckbox();
    }
}

public class MacFactory implements GUIFactory {
    @Override
    public Button createButton() {
        return new MacButton();
    }

    @Override
    public Checkbox createCheckbox() {
        return new MacCheckbox();
    }
}

Patrons Estructurals

Adapter

El patró Adapter permet que classes amb interfícies incompatibles treballin juntes.

public interface Target {
    void request();
}

public class Adaptee {
    public void specificRequest() {
        System.out.println("Specific request");
    }
}

public class Adapter implements Target {
    private Adaptee adaptee;

    public Adapter(Adaptee adaptee) {
        this.adaptee = adaptee;
    }

    @Override
    public void request() {
        adaptee.specificRequest();
    }
}

Decorator

El patró Decorator permet afegir funcionalitats a objectes de manera dinàmica.

public interface Component {
    void operation();
}

public class ConcreteComponent implements Component {
    @Override
    public void operation() {
        System.out.println("ConcreteComponent operation");
    }
}

public abstract class Decorator implements Component {
    protected Component component;

    public Decorator(Component component) {
        this.component = component;
    }

    @Override
    public void operation() {
        component.operation();
    }
}

public class ConcreteDecoratorA extends Decorator {
    public ConcreteDecoratorA(Component component) {
        super(component);
    }

    @Override
    public void operation() {
        super.operation();
        System.out.println("ConcreteDecoratorA operation");
    }
}

Facade

El patró Facade proporciona una interfície simplificada a un conjunt de subsistemes.

public class SubsystemA {
    public void operationA() {
        System.out.println("SubsystemA operation");
    }
}

public class SubsystemB {
    public void operationB() {
        System.out.println("SubsystemB operation");
    }
}

public class Facade {
    private SubsystemA subsystemA;
    private SubsystemB subsystemB;

    public Facade() {
        subsystemA = new SubsystemA();
        subsystemB = new SubsystemB();
    }

    public void operation() {
        subsystemA.operationA();
        subsystemB.operationB();
    }
}

Patrons de Comportament

Observer

El patró Observer defineix una dependència un-a-molts entre objectes, de manera que quan un objecte canvia d'estat, tots els seus dependents són notificats i actualitzats automàticament.

import java.util.ArrayList;
import java.util.List;

public interface Observer {
    void update(String message);
}

public class ConcreteObserver implements Observer {
    private String name;

    public ConcreteObserver(String name) {
        this.name = name;
    }

    @Override
    public void update(String message) {
        System.out.println(name + " received: " + message);
    }
}

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

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

    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }

    public void notifyObservers(String message) {
        for (Observer observer : observers) {
            observer.update(message);
        }
    }
}

Strategy

El patró Strategy permet definir una família d'algoritmes, encapsular-los i fer-los intercanviables.

public interface Strategy {
    void execute();
}

public class ConcreteStrategyA implements Strategy {
    @Override
    public void execute() {
        System.out.println("Strategy A");
    }
}

public class ConcreteStrategyB implements Strategy {
    @Override
    public void execute() {
        System.out.println("Strategy B");
    }
}

public class Context {
    private Strategy strategy;

    public void setStrategy(Strategy strategy) {
        this.strategy = strategy;
    }

    public void executeStrategy() {
        strategy.execute();
    }
}

Command

El patró Command encapsula una petició com un objecte, permetent parametritzar clients amb cues, registres i operacions reversibles.

public interface Command {
    void execute();
}

public class Light {
    public void on() {
        System.out.println("Light is on");
    }

    public void off() {
        System.out.println("Light is off");
    }
}

public class LightOnCommand implements Command {
    private Light light;

    public LightOnCommand(Light light) {
        this.light = light;
    }

    @Override
    public void execute() {
        light.on();
    }
}

public class LightOffCommand implements Command {
    private Light light;

    public LightOffCommand(Light light) {
        this.light = light;
    }

    @Override
    public void execute() {
        light.off();
    }
}

public class RemoteControl {
    private Command command;

    public void setCommand(Command command) {
        this.command = command;
    }

    public void pressButton() {
        command.execute();
    }
}

Exercicis Pràctics

  1. Implementa el patró Singleton: Crea una classe Singleton per gestionar la configuració d'una aplicació.
  2. Utilitza el patró Factory Method: Implementa una fàbrica per crear diferents tipus de documents (PDF, Word, etc.).
  3. Aplica el patró Observer: Crea un sistema de notificacions on diversos usuaris poden subscriure's a actualitzacions d'un servei.

Conclusió

Els patrons de disseny són eines poderoses que poden millorar significativament la qualitat del teu codi. En aquest tema, hem explorat alguns dels patrons més comuns i com implementar-los en Java. Practicar aquests patrons t'ajudarà a reconèixer situacions on poden ser aplicats i a utilitzar-los de manera efectiva en els teus projectes.

Curs de Programació en Java

Mòdul 1: Introducció a Java

Mòdul 2: Flux de Control

Mòdul 3: Programació Orientada a Objectes

Mòdul 4: Programació Orientada a Objectes Avançada

Mòdul 5: Estructures de Dades i Col·leccions

Mòdul 6: Gestió d'Excepcions

Mòdul 7: Entrada/Sortida de Fitxers

Mòdul 8: Multithreading i Concurrència

Mòdul 9: Xarxes

Mòdul 10: Temes Avançats

Mòdul 11: Frameworks i Llibreries de Java

Mòdul 12: Construcció d'Aplicacions del Món Real

© Copyright 2024. Tots els drets reservats