Introducció al Patró Observer
El patró Observer és un dels patrons de disseny de comportament més utilitzats en el desenvolupament de programari. Aquest patró defineix una relació de dependència un-a-molts entre objectes, de manera que quan un objecte canvia el seu estat, tots els seus dependents són notificats i actualitzats automàticament.
Objectius del Patró Observer
- Desacoblar el subjecte dels seus observadors: Permet que els objectes es comuniquin sense conèixer les identitats dels altres.
- Facilitar la reutilització del codi: Els observadors poden ser reutilitzats en diferents contextos sense modificar el subjecte.
- Promoure la flexibilitat i l'escalabilitat: Afegir nous observadors no requereix canvis en el subjecte.
Components del Patró Observer
El patró Observer consta de quatre components principals:
- Subject (Subjecte): Manté una llista d'observadors i proporciona mètodes per afegir, eliminar i notificar observadors.
- Observer (Observador): Defineix una interfície per actualitzar-se en resposta a canvis en el subjecte.
- ConcreteSubject (Subjecte Concret): Implementa el subjecte i manté l'estat d'interès per als observadors.
- ConcreteObserver (Observador Concret): Implementa l'actualització per mantenir la seva consistència amb el subjecte.
Diagrama UML del Patró Observer
+-----------------+ +-----------------+ | Subject |<----->| Observer | +-----------------+ +-----------------+ | + attach() | | + update() | | + detach() | +-----------------+ | + notify() | +-----------------+ ^ | | +---------------------+ | ConcreteSubject | +---------------------+ | - state | | + getState() | | + setState() | +---------------------+ ^ | | +---------------------+ | ConcreteObserver | +---------------------+ | - subject | | - state | | + update() | +---------------------+
Implementació del Patró Observer
A continuació es mostra una implementació del patró Observer en Python:
Subjecte i Observador
from abc import ABC, abstractmethod class Subject(ABC): def __init__(self): self._observers = [] def attach(self, observer): self._observers.append(observer) def detach(self, observer): self._observers.remove(observer) def notify(self): for observer in self._observers: observer.update(self) class Observer(ABC): @abstractmethod def update(self, subject): pass
Subjecte Concret
class ConcreteSubject(Subject): def __init__(self): super().__init__() self._state = None @property def state(self): return self._state @state.setter def state(self, value): self._state = value self.notify()
Observador Concret
class ConcreteObserver(Observer): def __init__(self, name): self._name = name self._state = None def update(self, subject): self._state = subject.state print(f'{self._name} ha estat notificat. Nou estat: {self._state}')
Exemple d'Ús
if __name__ == "__main__": subject = ConcreteSubject() observer1 = ConcreteObserver("Observador 1") observer2 = ConcreteObserver("Observador 2") subject.attach(observer1) subject.attach(observer2) subject.state = "Estat 1" subject.state = "Estat 2" subject.detach(observer1) subject.state = "Estat 3"
Exercicis Pràctics
Exercici 1: Implementar un Sistema de Notificació de Temperatura
Descripció: Implementa un sistema de notificació de temperatura on diversos dispositius (observadors) reben actualitzacions quan la temperatura (subjecte) canvia.
Requisits:
- Crea una classe
TemperatureSensor
que actuï com a subjecte. - Crea classes
DisplayDevice
iLoggingDevice
que actuïn com a observadors. - Quan la temperatura canviï, els dispositius han de ser notificats i han de mostrar o registrar la nova temperatura.
Solució Proposada
class TemperatureSensor(Subject): def __init__(self): super().__init__() self._temperature = None @property def temperature(self): return self._temperature @temperature.setter def temperature(self, value): self._temperature = value self.notify() class DisplayDevice(Observer): def update(self, subject): print(f'Display: La nova temperatura és {subject.temperature}°C') class LoggingDevice(Observer): def update(self, subject): print(f'Log: Temperatura registrada: {subject.temperature}°C') if __name__ == "__main__": sensor = TemperatureSensor() display = DisplayDevice() logger = LoggingDevice() sensor.attach(display) sensor.attach(logger) sensor.temperature = 25 sensor.temperature = 30
Errors Comuns i Consells
Errors Comuns
- No notificar els observadors després d'un canvi d'estat: Assegura't de cridar el mètode
notify()
després de canviar l'estat del subjecte. - No desacoblar correctament el subjecte dels observadors: Utilitza interfícies o classes abstractes per definir els observadors i subjectes, permetent així una major flexibilitat i reutilització.
Consells
- Utilitza patrons de disseny complementaris: El patró Observer es pot combinar amb altres patrons com el Singleton per assegurar que només hi hagi una instància del subjecte.
- Gestiona les dependències: Assegura't que els observadors es registrin i es desregistrin correctament per evitar referències pendents que podrien causar fuites de memòria.
Resum
El patró Observer és una eina poderosa per gestionar la comunicació entre objectes en un sistema desacoblat. Permet que els objectes es notifiquin automàticament dels canvis d'estat, facilitant la mantenibilitat i l'escalabilitat del codi. Amb una comprensió clara dels seus components i una implementació adequada, aquest patró pot millorar significativament la qualitat del teu programari.
Curs de Patrons de Disseny de Programari
Mòdul 1: Introducció als Patrons de Disseny
- Què són els Patrons de Disseny?
- Història i Origen dels Patrons de Disseny
- Classificació dels Patrons de Disseny
- Avantatges i Desavantatges d'Usar Patrons de Disseny
Mòdul 2: Patrons Creacionals
Mòdul 3: Patrons Estructurals
Mòdul 4: Patrons de Comportament
- Introducció als Patrons de Comportament
- Chain of Responsibility
- Command
- Interpreter
- Iterator
- Mediator
- Memento
- Observer
- State
- Strategy
- Template Method
- Visitor
Mòdul 5: Aplicació de Patrons de Disseny
- Com Seleccionar el Patró Adequat
- Exemples Pràctics d'Ús de Patrons
- Patrons de Disseny en Projectes Reals
- Refactorització Usant Patrons de Disseny
Mòdul 6: Patrons de Disseny Avançats
- Patrons de Disseny en Arquitectures Modernes
- Patrons de Disseny en Microserveis
- Patrons de Disseny en Sistemes Distribuïts
- Patrons de Disseny en Desenvolupament Àgil