Els patrons de disseny són solucions provades i reutilitzables per problemes comuns en el desenvolupament de programari. Aquests patrons ajuden a crear codi més robust, mantenible i escalable. En aquesta secció, explorarem els conceptes bàsics dels patrons de disseny, els tipus de patrons més comuns i alguns exemples pràctics.
Conceptes Bàsics dels Patrons de Disseny
Què és un Patró de Disseny?
Un patró de disseny és una descripció o plantilla per resoldre un problema que es pot utilitzar en moltes situacions diferents. Els patrons de disseny no són codi específic, sinó més aviat una guia sobre com estructurar el codi per abordar un problema particular.
Beneficis dels Patrons de Disseny
- Reutilització del Codi: Permeten reutilitzar solucions provades, reduint el temps de desenvolupament.
- Mantenibilitat: Faciliten la comprensió i el manteniment del codi.
- Escalabilitat: Ajuden a crear sistemes que poden créixer i adaptar-se a noves necessitats.
- Comunicació: Proporcionen un llenguatge comú per als desenvolupadors, facilitant la comunicació d'idees complexes.
Tipus de Patrons de Disseny
Els patrons de disseny es poden classificar en tres categories principals:
- Patrons Creacionals: Ajuden a crear objectes de manera que s'adeqüin a la situació donada.
- Patrons Estructurals: Ajuden a compondre objectes i classes en estructures més grans.
- Patrons de Comportament: Ajuden a definir com els objectes interactuen i es comuniquen entre ells.
Patrons Creacionals
- Singleton: Assegura que una classe només tingui una instància i proporciona un punt d'accés global a aquesta instància.
- Factory Method: Defineix una interfície per crear un objecte, però permet a les subclasses alterar el tipus d'objecte que es crearà.
- Abstract Factory: Proporciona una interfície per crear famílies d'objectes relacionats o dependents sense especificar les seves classes concretes.
Patrons Estructurals
- Adapter: Permet que interfícies incompatibles treballin juntes.
- Decorator: Afegeix funcionalitat addicional a un objecte de manera dinàmica.
- Facade: Proporciona una interfície simplificada a un conjunt de classes o a un subsistema complex.
Patrons de Comportament
- 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.
- Strategy: Permet definir una família d'algoritmes, encapsular-los i fer-los intercanviables.
- Command: Encapsula una petició com un objecte, permetent així parametritzar clients amb cues, peticions i operacions reversibles.
Exemples Pràctics
Exemple 1: 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ó de noves instàncies } public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }
Exemple 2: 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; interface Observer { void update(String message); } 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); } } 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); } } }
Exemple 3: Strategy
El patró Strategy permet definir una família d'algoritmes, encapsular-los i fer-los intercanviables.
interface Strategy { void execute(); } class ConcreteStrategyA implements Strategy { @Override public void execute() { System.out.println("Strategy A executed"); } } class ConcreteStrategyB implements Strategy { @Override public void execute() { System.out.println("Strategy B executed"); } } class Context { private Strategy strategy; public void setStrategy(Strategy strategy) { this.strategy = strategy; } public void executeStrategy() { strategy.execute(); } }
Exercicis Pràctics
Exercici 1: Implementar el Patró Singleton
Implementa una classe Singleton en el teu llenguatge de programació preferit. Assegura't que només es pugui crear una instància de la classe.
Exercici 2: Implementar el Patró Observer
Crea un sistema de notificació utilitzant el patró Observer. Implementa una classe Subject que pugui afegir, eliminar i notificar observadors.
Exercici 3: Implementar el Patró Strategy
Implementa una aplicació que utilitzi el patró Strategy per executar diferents algoritmes de càlcul (per exemple, sumar, restar, multiplicar).
Solucions
Solució 1: Singleton en Python
class Singleton: _instance = None def __new__(cls): if cls._instance is None: cls._instance = super(Singleton, cls).__new__(cls) return cls._instance
Solució 2: Observer en Python
class Observer: def update(self, message): pass class ConcreteObserver(Observer): def __init__(self, name): self.name = name def update(self, message): print(f"{self.name} received: {message}") class Subject: def __init__(self): self.observers = [] def add_observer(self, observer): self.observers.append(observer) def remove_observer(self, observer): self.observers.remove(observer) def notify_observers(self, message): for observer in self.observers: observer.update(message)
Solució 3: Strategy en Python
class Strategy: def execute(self): pass class ConcreteStrategyA(Strategy): def execute(self): print("Strategy A executed") class ConcreteStrategyB(Strategy): def execute(self): print("Strategy B executed") class Context: def __init__(self): self.strategy = None def set_strategy(self, strategy): self.strategy = strategy def execute_strategy(self): self.strategy.execute()
Conclusió
Els patrons de disseny són eines poderoses per als desenvolupadors de programari. Ajuden a crear codi més net, mantenible i escalable. En aquesta secció, hem explorat els conceptes bàsics dels patrons de disseny, els tipus de patrons més comuns i alguns exemples pràctics. Amb la pràctica, els patrons de disseny es convertiran en una part natural del teu procés de desenvolupament.
Arquitectures de Sistemes: Principis i Pràctiques per Dissenyar Arquitectures Tecnològiques Robustes i Escalables
Mòdul 1: Introducció a les Arquitectures de Sistemes
- Conceptes Bàsics d'Arquitectura de Sistemes
- Importància d'una Bona Arquitectura
- Tipus d'Arquitectures de Sistemes
Mòdul 2: Principis de Disseny d'Arquitectures
Mòdul 3: Components d'una Arquitectura de Sistemes
Mòdul 4: Escalabilitat i Rendiment
Mòdul 5: Seguretat en Arquitectures de Sistemes
Mòdul 6: Eines i Tecnologies
Mòdul 7: Casos d'Estudi i Exemples Pràctics
- Cas d'Estudi: Arquitectura d'un Sistema de Comerç Electrònic
- Cas d'Estudi: Arquitectura d'una Aplicació de Xarxes Socials
- Exercicis Pràctics