Introducció al Patró Mediator
El patró Mediator és un patró de disseny de comportament que permet reduir les dependències entre objectes comunicant-se a través d'un objecte intermediari, anomenat "mediador". Aquest patró facilita la comunicació entre objectes sense que aquests hagin de referenciar-se directament, promovent així un acoblament més baix i una major flexibilitat en el sistema.
Objectius del Patró Mediator
- Reduir les dependències entre objectes: Els objectes no necessiten conèixer-se directament, sinó que es comuniquen a través del mediador.
- Facilitar la modificació i extensió del sistema: Afegir o modificar la comunicació entre objectes es fa més senzill, ja que només cal ajustar el mediador.
- Millorar la llegibilitat i mantenibilitat del codi: El codi es torna més net i fàcil de seguir, ja que les interaccions complexes es gestionen en un sol lloc.
Estructura del Patró Mediator
El patró Mediator es compon dels següents elements:
- Mediator (Mediador): Defineix la interfície per a la comunicació amb els Colleagues.
- ConcreteMediator (Mediador Concret): Implementa la interfície Mediator i coordina la comunicació entre els Colleagues.
- Colleague (Col·lega): Cada objecte que participa en la comunicació. Coneix el Mediator però no altres Colleagues.
- ConcreteColleague (Col·lega Concret): Implementa el comportament específic dels Colleagues i utilitza el Mediator per comunicar-se amb altres Colleagues.
Diagrama UML
+-----------------+ +---------------------+ | Colleague | | Mediator | |-----------------| |---------------------| | - mediator: Mediator |<----->| + notify(sender: Colleague, event: string): void | |-----------------| |---------------------| | + notify(event: string): void | +---------------------+ +-----------------+ | ConcreteMediator | |---------------------| | - colleagues: List<Colleague> | |---------------------| | + notify(sender: Colleague, event: string): void | +---------------------+
Exemple Pràctic
Escenari
Suposem que estem desenvolupant una aplicació de xat on diversos usuaris poden enviar missatges entre ells. Utilitzarem el patró Mediator per gestionar la comunicació entre els usuaris.
Implementació
Mediator Interface
public interface ChatMediator { void sendMessage(String message, User user); void addUser(User user); }
ConcreteMediator
import java.util.ArrayList; import java.util.List; public class ChatMediatorImpl implements ChatMediator { private List<User> users; public ChatMediatorImpl() { this.users = new ArrayList<>(); } @Override public void addUser(User user) { this.users.add(user); } @Override public void sendMessage(String message, User user) { for (User u : this.users) { // No enviar el missatge a l'usuari que l'ha enviat if (u != user) { u.receive(message); } } } }
Colleague
public abstract class User { protected ChatMediator mediator; protected String name; public User(ChatMediator mediator, String name) { this.mediator = mediator; this.name = name; } public abstract void send(String message); public abstract void receive(String message); }
ConcreteColleague
public class UserImpl extends User { public UserImpl(ChatMediator mediator, String name) { super(mediator, name); } @Override public void send(String message) { System.out.println(this.name + ": Enviant missatge = " + message); mediator.sendMessage(message, this); } @Override public void receive(String message) { System.out.println(this.name + ": Rebut missatge = " + message); } }
Client
public class MediatorPatternDemo { public static void main(String[] args) { ChatMediator mediator = new ChatMediatorImpl(); User user1 = new UserImpl(mediator, "Alice"); User user2 = new UserImpl(mediator, "Bob"); User user3 = new UserImpl(mediator, "Charlie"); User user4 = new UserImpl(mediator, "Diana"); mediator.addUser(user1); mediator.addUser(user2); mediator.addUser(user3); mediator.addUser(user4); user1.send("Hola a tots!"); } }
Explicació del Codi
- ChatMediator Interface: Defineix els mètodes per enviar missatges i afegir usuaris.
- ChatMediatorImpl: Implementa la interfície ChatMediator. Gestiona una llista d'usuaris i envia missatges a tots els usuaris excepte l'emissor.
- User: Classe abstracta que representa un usuari. Conté referències al mediador i el nom de l'usuari.
- UserImpl: Implementa els mètodes send i receive per enviar i rebre missatges.
- MediatorPatternDemo: Classe client que crea el mediador, afegeix usuaris i envia un missatge.
Exercici Pràctic
Enunciat
Implementa un sistema de control de trànsit aeri utilitzant el patró Mediator. El sistema ha de permetre que els avions es comuniquin amb la torre de control per obtenir permís per aterrar o enlairar-se.
Solució
Mediator Interface
public interface AirTrafficControl { void requestLanding(Airplane airplane); void requestTakeoff(Airplane airplane); void addAirplane(Airplane airplane); }
ConcreteMediator
import java.util.ArrayList; import java.util.List; public class AirTrafficControlImpl implements AirTrafficControl { private List<Airplane> airplanes; public AirTrafficControlImpl() { this.airplanes = new ArrayList<>(); } @Override public void addAirplane(Airplane airplane) { this.airplanes.add(airplane); } @Override public void requestLanding(Airplane airplane) { System.out.println("Torre de Control: Permís per aterrar concedit a " + airplane.getName()); } @Override public void requestTakeoff(Airplane airplane) { System.out.println("Torre de Control: Permís per enlairar-se concedit a " + airplane.getName()); } }
Colleague
public abstract class Airplane { protected AirTrafficControl control; protected String name; public Airplane(AirTrafficControl control, String name) { this.control = control; this.name = name; } public String getName() { return name; } public abstract void requestLanding(); public abstract void requestTakeoff(); }
ConcreteColleague
public class AirplaneImpl extends Airplane { public AirplaneImpl(AirTrafficControl control, String name) { super(control, name); } @Override public void requestLanding() { System.out.println(this.name + ": Sol·licitant permís per aterrar."); control.requestLanding(this); } @Override public void requestTakeoff() { System.out.println(this.name + ": Sol·licitant permís per enlairar-se."); control.requestTakeoff(this); } }
Client
public class MediatorPatternAirTrafficControlDemo { public static void main(String[] args) { AirTrafficControl control = new AirTrafficControlImpl(); Airplane airplane1 = new AirplaneImpl(control, "Avió 1"); Airplane airplane2 = new AirplaneImpl(control, "Avió 2"); control.addAirplane(airplane1); control.addAirplane(airplane2); airplane1.requestLanding(); airplane2.requestTakeoff(); } }
Explicació del Codi
- AirTrafficControl Interface: Defineix els mètodes per sol·licitar aterratges i enlairaments, i per afegir avions.
- AirTrafficControlImpl: Implementa la interfície AirTrafficControl. Gestiona una llista d'avions i concedeix permisos per aterrar i enlairar-se.
- Airplane: Classe abstracta que representa un avió. Conté referències al control de trànsit aeri i el nom de l'avió.
- AirplaneImpl: Implementa els mètodes requestLanding i requestTakeoff per sol·licitar permisos.
- MediatorPatternAirTrafficControlDemo: Classe client que crea el control de trànsit aeri, afegeix avions i sol·licita permisos per aterrar i enlairar-se.
Conclusió
El patró Mediator és una eina poderosa per gestionar la comunicació entre objectes en sistemes complexos. Redueix les dependències directes entre objectes, facilitant la modificació i extensió del sistema. En aquest mòdul, hem vist la teoria del patró Mediator, un exemple pràctic d'una aplicació de xat i un exercici pràctic de control de trànsit aeri. Amb aquests coneixements, estàs preparat per aplicar el patró Mediator en els teus projectes de 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