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
- Implementa el patró Singleton: Crea una classe Singleton per gestionar la configuració d'una aplicació.
- Utilitza el patró Factory Method: Implementa una fàbrica per crear diferents tipus de documents (PDF, Word, etc.).
- 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
- Introducció a Java
- Configuració de l'Entorn de Desenvolupament
- Sintaxi i Estructura Bàsica
- Variables i Tipus de Dades
- Operadors
Mòdul 2: Flux de Control
Mòdul 3: Programació Orientada a Objectes
- Introducció a la POO
- Classes i Objectes
- Mètodes
- Constructors
- Herència
- Polimorfisme
- Encapsulació
- Abstracció
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
- Lectura de Fitxers
- Escriptura de Fitxers
- Fluxos de Fitxers
- BufferedReader i BufferedWriter
- Serialització
Mòdul 8: Multithreading i Concurrència
- Introducció al Multithreading
- Creació de Fils
- Cicle de Vida dels Fils
- Sincronització
- Utilitats de Concurrència
Mòdul 9: Xarxes
- Introducció a les Xarxes
- Sockets
- ServerSocket
- DatagramSocket i DatagramPacket
- URL i HttpURLConnection