El patrón Mediator (Mediador) tiene como objetivo reducir la complejidad de las comunicaciones entre múltiples objetos o clases.
Para lograr esto, centraliza la interacción entre los componentes en un solo lugar, el mediador, evitando que los componentes se comuniquen entre sí explícitamente.
Un mediador que facilita las cosas.
El patrón Mediator se enfoca en situaciones con:
Alto Acoplamiento entre Clases: En sistemas con muchas clases interconectadas, el cambio en una clase puede afectar a otras, lo que lleva a un sistema frágil y difícil de mantener.
Complejidad en la Comunicación: La gestión de la comunicación entre múltiples clases o componentes puede volverse compleja y difícil de entender y mantener.
El patrón Mediator propone las siguientes soluciones:
Centralizar la Comunicación: En lugar de que las clases se comuniquen directamente entre sí, lo hacen a través de un objeto mediador central.
Simplificar el Diseño: Reduce la complejidad de la comunicación, al centralizar el control y la lógica de la interacción entre objetos.
Este patrón es recomendable cuando:
Reduce el Acoplamiento: Al centralizar la comunicación, disminuye el acoplamiento entre las clases o componentes.
Simplifica la Mantenibilidad: Facilita el mantenimiento y la actualización del código, ya que los cambios en la lógica de comunicación se realizan en un solo lugar.
Mejora la Organización del Código: Centraliza la lógica de interacción, lo que puede mejorar la organización y la claridad del código.
Puede Crear un ‘Objeto Dios’: El mediador puede llegar a ser muy complejo y asumir demasiadas responsabilidades, convirtiéndose en un cuello de botella.
Rendimiento: La centralización de la comunicación puede afectar el rendimiento, especialmente en sistemas con alta carga de mensajes.
Complejidad en el Mediador: El propio mediador puede volverse complejo y difícil de manejar si no se diseña cuidadosamente.
Debemos crear un sistema de control de tráfico aéreo para gestionar el espacio aéreo de un aeropuerto concurrido.
Este sistema necesita manejar múltiples componentes, como torres de control, aviones en vuelo, servicios en tierra y pistas de aterrizaje.
El principal desafío es el manejo de la comunicación y la coordinación compleja y en tiempo real entre todos estos componentes.
Cada componente tiene su propia lógica y necesidades de información, pero también debe trabajar en armonía con los demás, para garantizar un funcionamiento seguro y eficiente del aeropuerto.
Una comunicación directa y múltiple entre estos componentes puede llevar a un sistema altamente acoplado y difícil de mantener o escalar.
Elegimos el patrón Mediator para centralizar y simplificar las interacciones entre los componentes del sistema.
Al tener un mediador central, podemos tener un punto de control y coordinación que gestione cómo y cuándo se comunican los componentes. Esto reduce el acoplamiento y facilita la gestión y expansión del sistema.
Definimos la interfaz AirTrafficMediator que registra componentes y envía mensajes. El mediador concreto es la Torre de Control, que tiene una lista de componentes. Definimos la interfaz AirTrafficComponent que es una base para aviones y pistas, y los colegas concretos, Airplane y Runway, ambos reciben mensajes pero el Airplane también envía alertas, por ejemplo para aterrizar. El AirportSystem es el cliente, configura el sistema y simula la comunicación.
Codificamos en Java lo que preparamos en el diagrama.
Creamos la Interfaz Mediator:
interface AirTrafficControlMediator {
void registerComponent(AirTrafficComponent component);
void sendMessage(String message, AirTrafficComponent originator);
}
Implementamos el ConcreteMediator:
class ControlTowerMediator implements AirTrafficControlMediator {
private List components = new ArrayList<>();
@Override
public void registerComponent(AirTrafficComponent component) {
components.add(component);
}
@Override
public void sendMessage(String message, AirTrafficComponent originator) {
for (AirTrafficComponent component : components) {
// No envia mensaje al originador
if (component != originator) {
component.receiveMessage(message);
}
}
}
}
Definimos la interfaz Colleague:
abstract class AirTrafficComponent {
protected AirTrafficControlMediator mediator;
public AirTrafficComponent(AirTrafficControlMediator mediator) {
this.mediator = mediator;
}
public abstract void receiveMessage(String message);
}
Implementamos las Colleague clases:
class Airplane extends AirTrafficComponent {
public Airplane(AirTrafficControlMediator mediator) {
super(mediator);
}
@Override
public void receiveMessage(String message) {
System.out.println(“Avión recibió: ” + message);
}
public void sendAlert(String message) {
System.out.println(“Avión envía alerta: ” + message);
mediator.sendMessage(message, this);
}
}
class Runway extends AirTrafficComponent {
public Runway(AirTrafficControlMediator mediator) {
super(mediator);
}
@Override
public void receiveMessage(String message) {
System.out.println(“Pista recibió: ” + message);
}
}
El código cliente:
public class AirportSystem {
public static void main(String[] args) {
AirTrafficControlMediator mediator = new ControlTowerMediator();
Airplane airplane1 = new Airplane(mediator);
Runway mainRunway = new Runway(mediator);
mediator.registerComponent(airplane1);
mediator.registerComponent(mainRunway);
airplane1.sendAlert(“Solicitando aterrizaje.”);
}
}
Los participantes que vimos antes son: Mediator, ConcreteMediator, Colleague, ConcreteColleague, Client:
Este ejemplo da una muestra del uso del patrón Mediator en el contexto de un sistema de control de tráfico aéreo.
Al aplicarlo vemos que reduce el acoplamiento y centraliza de la comunicación, facilitando el uso por parte del cliente.
Se suele usar junto a Mediator para mantener sincronizados los objetos Colleague.
Ambos se parecen, porque encapsulan y centralizan la complejidad, pero, mientras que Facade se enfoca en simplificar la interfaz hacia un conjunto de interfaces, Mediator se enfoca en centralizar la interacción entre objetos.