天天看點

Design Pattern - Behavioral Patterns - Mediator Pattern

2007
Design Pattern - Behavioral Patterns - Mediator Pattern
Section 5, Chapter 3

Mediator Pattern

Concept

The Mediator pattern allows groups of objects to communicate in a disassociated manner and encapsulates this communication while keeping the objects loosely coupled. The pattern allows objects to communicate on a one-to-one basis and acts as a proxy between objects to facilitate this communication.

Use

If you have a group of objects that need to communicate in some way, but you don't wish to allow them direct access to one another, then using this pattern would be a way to encapsulate this communication in a single object. You find yourself needing to have several objects of similar types communicate in some way with each other. But often this communication can become too entangled and the methods of communication too deeply coupled or too rigid to make changes easily.

Design

The Mediator pattern has two main classes associated with it: the Mediator and the Colleague. The mediator acts as a go-between to the colleagues and controls which two colleagues communicate.

Design Pattern - Behavioral Patterns - Mediator Pattern

Illustration

Design Pattern - Behavioral Patterns - Mediator Pattern
interface IMessageEngine
{
	void Register(MessageThread thread);
	void Send(string from, string to, string message);
}
           
class MessageEngine : IMessageEngine
{
	private Hashtable _messageThreads = new Hashtable();
	public void Register(MessageThread thread)
	{
		if(!_messageThreads.ContainsKey(thread.Name))
			_messageThreads.Add(thread.Name,thread);
		thread.MessageEngine = this;
	}
	public void Send(string from, string to, string message)
	{
		MessageThread thread = (MessageThread)_messageThreads[to];
		if(thread != null)
			thread.Receive(from, message);
	}
}
           
abstract class MessageThread
{
	private IMessageEngine _messageEngine;
	.....
	public IMessageEngine MessageEngine
	{
		set{ _messageEngine = value; }
		get{ return _messageEngine; }
	}
	public void Send(string to, string message)
	{
		_messageEngine.Send(_name, to, message);
	}
}
           
// lack a concrete class implmenting MessageThread here
           
//Create the message engine which is the mediator
IMessageEngine engine = new MessageEngine();
//instantiate two chat instance message windows
MessageThread imWindow = new IMWindow("Jazzy Jeff");
MessageThread chatWindow = new ChatWindow("Sir Chats-A-Lot");
//Register each chat instance window with the mediator
engine.Register(imWindow);
engine.Register(chatWindow);
//Jazzy Jeff sends a message to Sir Chats-A-Lot
imWindow.Send("Sir Chats-A-Lot","Hey Sir Chats-A-Lot!");
// Sir Chats-A-Lot sends a message back to Jazzy Jeff
chatWindow.Send("Jazzy Jeff","Hey Jazzy!");
           
Comment: according to the code syntax, it should be C#, however, this sample lacks the implementation of class IMWindow and ChatWindow.
Comment: this implementation only allow peer-to-peer communication.
December 2007
Design Pattern - Behavioral Patterns - Mediator Pattern
Section 2, Chapter 9
Design Pattern - Behavioral Patterns - Mediator Pattern

Use

  • There is protocol that is observed between the members of a group.
  • Messages might also be vetted for content.
  • The Mediator pattern makes provisions for more than one mediator.
Colleague Registers with a Mediator by supplying a Receive method; issues Send requests to other colleagues via the Mediator.
Mediator Broadcasts sent messages to all signed-on Colleagues using the Respond delegate.
class MediatorPattern {

	// Mediator Pattern Judith Bishop Sept 2007
	/* The Mediator maintains a list of colleagues and specifies the
	 communication methods that it can mediate - in this case, Send.
	 Receive is implemented at Colleague level and called via a delegate
	 supplied by the colleagues to the mediator on sign-on.
	*/

	class Mediator {

		public delegate void Callback(string message, string from);
		Callback respond;

		public void SignOn(Callback method)
		{
			respond += method;
		}

		public void Block(Callback method)
		{
			respond -= method;
		}
		
		public void Unblock(Callback method)
		{
			respond += method;
		}

		// Send is implemented as a broadcast
		public void Send(string message, string from)
		{
			respond(message, from);
			Console.WriteLine();
		}
	}

	class Colleague {
		Mediator mediator;
		protected string name;

		public Colleague(Mediator mediator, string name)
		{
			this.mediator = mediator;
			mediator.SignOn(Receive);
			this.name = name;
		}
		
		public virtual void Receive(string message, string from)
		{
			Console.WriteLine(name +" received from "+from+": " + message);
		}
		
		public void Send(string message)
		{
			Console.WriteLine("Send (From "+name+ "): "+message);
			mediator.Send(message, name);
		}
	}

	class ColleagueB : Colleague {
		public ColleagueB(Mediator mediator,string name) : base(mediator, name) {}

		// Does not get copies of own messages
		public override void Receive(string message, string from)
		{
			if (!String.Equals(from, name))
				Console.WriteLine(name +" received from "+from+": " + message);
		}
	}

	static void Main () {
		ediator m = new Mediator();
		// Two from head office and one from a branch office
		Colleague head1 = new Colleague(m,"John");
		ColleagueB branch1 = new ColleagueB(m,"David");
		Colleague head2 = new Colleague(m,"Lucy");

		head1.Send("Meeting on Tuesday, please all ack");
		branch1.Send("Ack"); // by design does not get a copy
		m.Block(branch1.Receive); // temporarily gets no messages
		head1.Send("Still awaiting some Acks");
		head2.Send("Ack");
		m.Unblock(branch1.Receive); // open again
		head1.Send("Thanks all");
	}
}
           
Comment: this implemetation allows broadcasting to all the other colleagues..
2016
Design Pattern - Behavioral Patterns - Mediator Pattern
Chapter 18
Design Pattern - Behavioral Patterns - Mediator Pattern
Comment: the stupid thing of this implementation is that it does not generalize the concept Friend, which is usually referred as colleague, it defines a class for each friend entity, that means for each entity that wants to join the party, you need a class for it.