Design Patterns - Mediator

Propósito

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.

Problema

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.

Solución

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.

Estructura

mediator

Participantes

  • Mediator: Define una interfaz para comunicarse con los objetos Colleague.
  • ConcreteMediator: Implementa la interfaz Mediator y coordina la comunicación entre objetos Colleague.
  • Colleague: Interfaz común para los objetos que deben comunicarse entre sí a través del Mediator.
  • ConcreteColleague: Clases que se comunican entre sí a través del Mediator.
  • Client: Usa el mediator

Cuándo Usarlo

Este patrón es recomendable cuando:

  • hay muchos objetos interactuando de forma compleja pero bien definida.
  • se quiere centralizar el control y la lógica de comunicación, de modo que cada objeto no necesite conocer el funcionamiento de los demás.

Ventajas

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.

Desventajas

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.

Ejemplo: Sistema de Control de Tráfico Áereo

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.

Problema

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.

Solución planteada

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.

mediator

Código Java

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.”);
      }
  }
              
              

Mapeo (del ejemplo a Participantes)

Los participantes que vimos antes son: Mediator, ConcreteMediator, Colleague, ConcreteColleague, Client:

  • AirTrafficMediator (Mediator): Interfaz que define métodos para registrar componentes y enviar mensajes.
  • ControlTower (ConcreteMediator): Concreta la torre de control que coordina la comunicación entre aviones y pistas.
  • AirTrafficComponent (Colleague): Componente abstracto del tráfico aéreo que proporciona una base para aviones y pistas.
  • Airplane (ConcreteColleague): Avión que comunica sus intenciones y recibe instrucciones a través del mediador.
  • Runway (ConcreteColleague): Pista que recibe información sobre aviones que buscan aterrizar y actúa en consecuencia.
  • AirportSystem (Client): Configura el sistema y simula la comunicación en el tráfico aéreo.

Conclusiones

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.

Patrones relacionados

  • Observer

Se suele usar junto a Mediator para mantener sincronizados los objetos Colleague.

  • Facade

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.