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:

  1. Mediator (Mediador): Defineix la interfície per a la comunicació amb els Colleagues.
  2. ConcreteMediator (Mediador Concret): Implementa la interfície Mediator i coordina la comunicació entre els Colleagues.
  3. Colleague (Col·lega): Cada objecte que participa en la comunicació. Coneix el Mediator però no altres Colleagues.
  4. 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

  1. ChatMediator Interface: Defineix els mètodes per enviar missatges i afegir usuaris.
  2. ChatMediatorImpl: Implementa la interfície ChatMediator. Gestiona una llista d'usuaris i envia missatges a tots els usuaris excepte l'emissor.
  3. User: Classe abstracta que representa un usuari. Conté referències al mediador i el nom de l'usuari.
  4. UserImpl: Implementa els mètodes send i receive per enviar i rebre missatges.
  5. 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

  1. AirTrafficControl Interface: Defineix els mètodes per sol·licitar aterratges i enlairaments, i per afegir avions.
  2. AirTrafficControlImpl: Implementa la interfície AirTrafficControl. Gestiona una llista d'avions i concedeix permisos per aterrar i enlairar-se.
  3. Airplane: Classe abstracta que representa un avió. Conté referències al control de trànsit aeri i el nom de l'avió.
  4. AirplaneImpl: Implementa els mètodes requestLanding i requestTakeoff per sol·licitar permisos.
  5. 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.

© Copyright 2024. Tots els drets reservats