Patrón mediador
En ingeniería de software, el patrón mediador define un objeto que encapsula cómo interactúa un conjunto de objetos. Este patrón se considera un patrón de comportamiento debido a la forma en que puede alterar el comportamiento de ejecución del programa.
En la programación orientada a objetos, los programas a menudo constan de muchas clases. La lógica empresarial y el cálculo se distribuyen entre estas clases. Sin embargo, a medida que se agregan más clases a un programa, especialmente durante el mantenimiento y/o la refactorización, el problema de la comunicación entre estas clases puede volverse más complejo. Esto hace que el programa sea más difícil de leer y mantener. Además, puede resultar difícil cambiar el programa, ya que cualquier cambio puede afectar el código en varias otras clases.
Con el patrón mediador, la comunicación entre objetos se encapsula dentro de un objeto mediador. Los objetos ya no se comunican directamente entre sí, sino que se comunican a través del mediador. Esto reduce las dependencias entre los objetos que se comunican, reduciendo así el acoplamiento.
Resumen
El patrón de diseño mediador es uno de los veintitrés patrones de diseño conocidos que describen cómo resolver problemas de diseño recurrentes para diseñar software orientado a objetos flexible y reutilizable, es decir, objetos que son más fáciles de implementar, cambiar, probar y reutilizar.
Problemas que el patrón de diseño del mediador puede resolver
- Debe evitarse el acoplamiento entre un conjunto de objetos que interactúan.
- Debe ser posible cambiar la interacción entre un conjunto de objetos independientemente.
Definir un conjunto de objetos que interactúan accediendo y actualizándose entre sí directamente es inflexible porque vincula estrechamente los objetos entre sí y hace que sea imposible cambiar la interacción independientemente de (sin tener que cambiar) los objetos. Y evita que los objetos sean reutilizables y los hace difíciles de probar.
Los objetos fuertemente acoplados son difíciles de implementar, cambiar, probar y reutilizar porque se refieren y conocen muchos objetos diferentes.
Soluciones descritas por el patrón de diseño del mediador
- Define un objeto separado (mediador) que encapsula la interacción entre un conjunto de objetos.
- Los objetos delegan su interacción a un objeto mediador en lugar de interactuar entre sí directamente.
Los objetos interactúan entre sí indirectamente a través de un objeto mediador que controla y coordina la interacción.
Esto hace que los objetos se acoplen débilmente. Solo se refieren y saben de su objeto mediador y no tienen conocimiento explícito el uno del otro.
Vea también la clase UML y el diagrama de secuencia a continuación.
Definición
La esencia del patrón mediador es "definir un objeto que encapsule cómo interactúa un conjunto de objetos". Promueve el acoplamiento débil al evitar que los objetos se refieran entre sí explícitamente y permite que su interacción varíe de forma independiente. Las clases de clientes pueden usar el mediador para enviar mensajes a otros clientes y pueden recibir mensajes de otros clientes a través de un evento en la clase de mediador.
Estructura
Clase UML y diagrama de secuencia
En el diagrama de clases UML anterior, las clases Colega1
y Colega2
no se refieren (ni se actualizan) entre sí directamente.
En cambio, se refieren a la interfaz común Mediator
para controlar y coordinar la interacción (mediate()
), lo que los hace independientes entre sí con respecto a cómo se lleva a cabo la interacción..
La clase Mediator1
implementa la interacción entre Colega1
y Colega2
.
El diagrama de secuencia UML muestra las interacciones en tiempo de ejecución. En este ejemplo, un objeto Mediator1
media (controla y coordina) la interacción entre los objetos Colega1
y Colega2
.
Suponiendo que Colega1
quiere interactuar con Colega2
(para actualizar/sincronizar su estado, por ejemplo), Colega1
llama a mediate (esto)
en el objeto Mediator1
, que obtiene los datos modificados de Colega1
y realiza una acción2()
en Colega2
.
A partir de entonces,
Colega2
llama a mediate(this)
en el objeto Mediator1
, que obtiene los datos modificados de Colega2
y realiza un acción1() en Colega1.
Diagrama de clases
- Participantes
Mediador: define la interfaz para la comunicación entre objetos Colega
ConcreteMediator: implementa la interfaz del mediador y coordina la comunicación entre los objetos Colega. Es consciente de todos los Colegas y sus propósitos con respecto a la intercomunicación.
Colega: define la interfaz para la comunicación con otros Colegas a través de su Mediador
ConcreteColleague: implementa la interfaz de Colega y se comunica con otros Colegas a través de su Mediador
Ejemplo
C#
El patrón de mediador garantiza que los componentes se acoplen libremente, de modo que no se llamen entre sí explícitamente, sino que lo hagan a través de llamadas a un mediador. En el siguiente ejemplo, el mediador registra todos los componentes y luego llama a sus métodos SetState.
interfaz IComponente{} vacío SetState()objeto estado);}clase Componente1 : IComponente{} interna vacío SetState()objeto estado) {} tiro nuevo No Implemented Excepción(); }}clase Componente2 : IComponente{} interna vacío SetState()objeto estado) {} tiro nuevo No Implemented Excepción(); }}// Media las tareas comunesclase Mediador{} interna IComponente Componente1 {} #; set; } interna IComponente Componente2 {} #; set; } interna vacío Cambio()objeto estado) {} esto.Componente1.SetState()estado); esto.Componente2.SetState()estado); }}
Una sala de chat podría usar el patrón de mediador, o un sistema en el que muchos "clientes" reciben un mensaje cada vez que uno de los otros clientes realiza una acción (para las salas de chat, esto sería cuando cada persona envía un mensaje). En realidad, usar el patrón de mediador para una sala de chat solo sería práctico cuando se usa con la comunicación remota. El uso de sockets sin procesar no permitiría las devoluciones de llamada de los delegados (personas suscritas al evento MessageReceived de la clase Mediator).
público delegado vacío MensajeRecibidoEventHandler()cuerda Mensaje, cuerda sender);público clase Mediador{} público evento MensajeRecibidoEventHandler MensajeRecibido; público vacío Enviar()cuerda Mensaje, cuerda sender) {} si ()MensajeRecibido ! nulo) {} Consola.WriteLine()"Enviando '{0} de {1}", Mensaje, sender); MensajeRecibido()Mensaje, sender); } }}público clase Persona{} privado Mediador _mediator; público cuerda Nombre {} #; set; } público Persona()Mediador mediador, cuerda Nombre) {} Nombre = Nombre; _mediator = mediador; _mediator.MensajeRecibido += nuevo MensajeRecibidoEventHandler()Recibido); } privado vacío Recibido()cuerda Mensaje, cuerda sender) {} si ()sender ! Nombre) Consola.WriteLine()"Recibido '{1} de {2}", Nombre, Mensaje, sender); } público vacío Enviar()cuerda Mensaje) {} _mediator.Enviar()Mensaje, Nombre); }}
Java
En el siguiente ejemplo, un objeto Mediator
controla los valores de varios objetos Storage
, obligando al código de usuario a acceder a los valores almacenados a través del mediador. Cuando un objeto de almacenamiento quiere emitir un evento que indica que su valor ha cambiado, también vuelve al objeto mediador (a través del método notifyObservers
) que controla la lista de observadores (implementado usando el patrón de observador).
importación java.util.HashMap;importación Java.util. Facultativo;importación java.util.concurrent.CopyOnWriteArrayList;importación java.util.función.Consumer;clase Almacenamiento.T■ {} T valor; T # Valor() {} retorno valor; } vacío setValue()Mediador.T■ mediador, String almacenamientoName, T valor) {} esto.valor = valor; mediador.notificación Observadores()almacenamientoName); }}clase Mediador.T■ {} privado final HashMap.String, Almacenamiento.T> almacenamientoMap = nuevo HashMap■(); privado final CopyOnWriteArrayList.Consumo.String> observadores = nuevo CopyOnWriteArrayList■(); público vacío setValue()String almacenamientoName, T valor) {} Almacenamiento almacenamiento = almacenamientoMap.computeIfAbsent()almacenamientoName, Nombre - nuevo Almacenamiento■()); almacenamiento.setValue()esto, almacenamientoName, valor); } público Facultativo.T■ # Valor()String almacenamientoName) {} retorno Facultativo.ofNullable()almacenamientoMap.#()almacenamientoName)).mapa()Almacenamiento::# Valor); } público vacío añadir Observer()String almacenamientoName, Runnable observador) {} observadores.añadir()eventName - {} si ()eventName.iguales()almacenamientoName) {} observador.Corre(); } }); } vacío notificación Observadores()String eventName) {} observadores.para cada uno()observador - observador.aceptar()eventName)); }}público clase MediatorDemo {} público estática vacío principal()String[] args) {} Mediador.Integer■ mediador = nuevo Mediador■(); mediador.setValue()"bob", 20); mediador.setValue()"alicia", 24); mediador.# Valor()"alicia").siPresente()Edad - Sistema.Fuera..println()"age for alice: " + Edad)); mediador.añadir Observer()"bob", () - {} Sistema.Fuera..println()"nueva era para bob: " + mediador.# Valor()"bob").oElseThrow()RuntimeException::nuevo)); }); mediador.setValue()"bob", 21); }}
Contenido relacionado
Grado de distorsión de arranque y parada
Reenviador de datos
Código de tiempo lineal