Intención del patrón
- Definir un objeto que encapsule como interactúan un conjunto de objetos. Este patrón promueve la pérdida de acoplamiento haciendo que dicho conjunto de objetos no estén referenciados entre ellos explicitamente. Esto permite variar su interacción de manera independiente.
- Diseñar un intermediario que permita desacoplar las parejas.
Ejemplo de problema
Se desea diseñar componentes reusables, pero las dependencias entre las posibles piezas reusables demuestran el fenómeno "código spaghetti".Discusión
En Unix, las credenciales para acceder a los recursos del sistema, son administradas en tres niveles de granularidad: Mundo, Grupo y Propietario (World, Group y Owner). Un grupo es una colección de usuarios previstos para modelar alguna afiliación funcional. Cada usuario en el sistema puede ser miembro de uno o más grupos y cada grupo puede tener cero o más usuarios asignados a él. La siguiente figura muestra tres usuarios que son asignados a los tres grupos existentes.Si fuéramos a modelar esto en software, deberíamos decidir tener objetos User acoplados a objetos Group y viceversa. Entonces, cuando ocurran cambios, ambas clases y todas sus instancias serán afectadas.
Un punto de vista alternativo podría ser introducir "un nivel adicional de indirección" (Tomando el mapeo de Usuarios a Grupos y Grupos a Usuarios, y creando una abstracción en sí misma. Esto ofrece varias ventajas: Usuarios y Grupos están desacoplados uno de otro, muchos mapeos pueden ser fácilmente mantenidos y manipulados simultáneamente y la abstracción de mapeo puede ser extendida en el futuro mediante la definición de clases derivadas.
Partiendo un sistema en muchos objetos, generalmente, mejora la reusabilidad, pero proliferan las interconecciones entre estos objetos tendiendo a reducirla nuevamente. El objeto Mediator: encapsula todas las interconecciones, actúa como el "centro" de comunicación, es el responsable de controlar y coordinar la interacción de sus clientes y promueve el desacoplamiento al evitar que los objetos se refieran unos a otros explícitamente.
El patrón Mediator promueve de una "relación de red de muchos a muchos" a "estatus de objeto completo"(full object status). Modelando las interrelaciones con un objeto mejora la encapsulación y le permite modificar o extender el comportamiento de éstas interrelaciones a través de la derivación de clases.
De esta manera, el patrón Mediator provee una manera flexible y no invasiva de administrar, por ejemplo, Usuarios y Grupos.
Estructura
Los colegas (o pares) no están acoplados entre sí. Cada uno "habla" con el Mediator, que a su vez, conoce y lleva a cabo la orquestación de los otros. El mapeo "muchos a muchos" entre colegas que podría existir, se ha "promovido a estatus de objeto completo". Esta nueva abstracción proporciona un lugar de indirección donde niveles adicionales pueden ser alojados.
Ejemplo
El patrón Mediator define un objeto que controla como interactúa un conjunto de objetos. El bajo acoplamiento entre objetos colegas, se consigue haciendo que los objetos colegas se comuniquen con el objeto Mediator en lugar de hacerlo entre ellos. La torre de control en un aeropuerto controlado, demuestra este patrón bastante bien. Los pilotos de los aviones que se aproximan o salen de la terminal, se comunican con la torre en lugar de hacerlo explícitamente entre ellos. Las restricciones sobre quien puede aterrizar o despegar son impuestas por la torre. Es importante notar que la torre no controla la totalidad de los vuelos, sino solamente los que se se encuentran en el área de la terminal.Check list
- Identificar una colección de objetos que interactúan entre sí que se podrían ver beneficiados con el mutuo desacople.
- Encapsular esas interacciones en la abstracción de una nueva clase.
- Crear una instancia de la nueva clase y redireccionar todas las parejas de objetos para que interactúen solamente con el objeto Mediator.
- Balancear el principio de desacople con el principio de distribución de la responsabilidad uniforme.
- Tener cuidado de no crear un objeto Controller o del tipo God.
Reglas de oro
- Chain of responsability, Command, Mediator y Observer muestran cómo se pueden desacoplar los Emisores de los Receptores, pero con diferentes ventajas. Chain of responsability pasa la petición de un Emisor a una cadena de posibles Receptores. Command normalmente especifica una relación Emisor-Receptor con una clase derivada. Mediator tiene Emisores y Receptores que se referencian entre ellos indirectamente. Observer define una interfaz bien desacoplada que permite a multiples Receptores ser configurados en tiempo de ejecución.
- Mediator y Observer son patrones que compiten. La diferencia entre ellos es que Observer distribuye la comunicación mediante la introducción de objetos "observador" y "sujeto", mientras que el objeto Mediator encapsula la comunicación entre otros objetos. Resulta más fácil hacer reutilizable a los Observadores y Sujetos que a los Mediators.
- Mediator es similar a Facade en que abstrae la funcionalidad de clases existentes. Mediator abstrae/centraliza la comunicación arbitraria entre objetos colegas, de manera rutinaria "agrega valor" y es conocido/referenciado el objeto colega (es decir, define un protocolo multidireccional). En contraste, Facade define una interfaz más simple a un subsistema, no agrega nueva funcionalidad y no es conocido por el subsistema de clases (por ejemplo, define un protocolo unidireccional en donde éste realiza peticiones al subsistema de clases pero no a la inversa.
Ejemplo de código en C#
using System;
using System.Collections;
class MainApp
{
static void Main()
{
ConcreteMediator m = new ConcreteMediator();
ConcreteColleague1 c1 = new ConcreteColleague1(m);
ConcreteColleague2 c2 = new ConcreteColleague2(m);
m.Colleague1 = c1;
m.Colleague2 = c2;
c1.Send("How are you?");
c2.Send("Fine, thanks");
// Wait for user
Console.Read();
}
}
// "Mediator"
abstract class Mediator
{
public abstract void Send(string message,
Colleague colleague);
}
// "ConcreteMediator"
class ConcreteMediator : Mediator
{
private ConcreteColleague1 colleague1;
private ConcreteColleague2 colleague2;
public ConcreteColleague1 Colleague1
{
set{ colleague1 = value; }
}
public ConcreteColleague2 Colleague2
{
set{ colleague2 = value; }
}
public override void Send(string message,
Colleague colleague)
{
if (colleague == colleague1)
{
colleague2.Notify(message);
}
else
{
colleague1.Notify(message);
}
}
}
// "Colleague"
abstract class Colleague
{
protected Mediator mediator;
// Constructor
public Colleague(Mediator mediator)
{
this.mediator = mediator;
}
}
// "ConcreteColleague1"
class ConcreteColleague1 : Colleague
{
// Constructor
public ConcreteColleague1(Mediator mediator)
: base(mediator)
{
}
public void Send(string message)
{
mediator.Send(message, this);
}
public void Notify(string message)
{
Console.WriteLine("Colleague1 gets message: "
+ message);
}
}
// "ConcreteColleague2"
class ConcreteColleague2 : Colleague
{
// Constructor
public ConcreteColleague2(Mediator mediator)
: base(mediator)
{
}
public void Send(string message)
{
mediator.Send(message, this);
}
public void Notify(string message)
{
Console.WriteLine("Colleague2 gets message: "
+ message);
}
}
0 comentarios:
Publicar un comentario
Muchas gracias por leer el post y comentarlo.