我们知道面向对象应用程序是由一组为了提供某种服务而彼此交互的对象组成。当彼此引用的对象数量比较少时,此时对象之间就为直接交互(点对点)。而当对象的数量增加时,这种直接交互会导致对象之间复杂的、混乱的引用,最后形成一张巨大的网,这就会影响应用程序的可维护性。同时,因为对象之间的高耦合,当一个对象直接引用其他的对象时,缩小了这些对象的复用范围。
因此:我们可使用一个“中介对象”来管理对象间的关联关系,避免相互交互的对象之间的紧耦合引用关系,从而更好地抵御变化。
以上的变化反映在下图:
中介者模式的相关角色如下图:
由图可知,它的角色有:
1、抽象同伴类角色 ColleagueBase。它是"具体同伴类角色"的基类,同时在它内部要引用到一个抽象中介类成员。
2、抽象中介类角色 MediatorBase。它是"具体中介类角色"的基类. 它定义了要求其子类必须完成的方法,此方法可以被具体同伴类角色调用。
3、具体同伴类角色 ConcreteColleague A/B. 它们都继承自"抽象同伴类角色 ColleagueBase",由具体同伴类角色所产生的实例化对象不再像以前那样相互之间直接联系,而是通过"具体中介类角色"进行统一协调和管理。在上图中所定义的Send和 Receive方法表示此类具有发送和接收信息的功能,但这时的发送和接收通讯是在ConcreteColleague 与Mediator之间进行,而不是在ConcreteColleague之间直接通讯,因为通过Mediator,它们与自己的同伴之间早就解除了耦合。
4、具体中介类角色ConcreteMediator. 它实现了抽象中介类角色所定义的通讯功能(此图中是Sendmessage功能)。但此功能是由具体同伴类角色实例ConcreteColleague来调用的,因为在具体中介类角色实例中保存了所有参与活动的具体同伴类角色实例的引用,它们在Mediator中介角色里集中放置与管理。当我们调用相关通讯功能时,通过中介者角色的管理,由它来决定信息通讯的目的地。
下面我们用代码来加以说明
我们有两段程序,一个用于演示中介者模式工作的基本流程,另一个我们使用中介者模式来模拟一个聊天室。
一、基本流程示例代码
1、抽象同伴类角色 AbsPeople
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MyMediator
{
abstract class AbsPeople
{
protected AbsMediator mediator;
#region 构造函数
public AbsPeople(AbsMediator mediator)
{
this.mediator = mediator;
}
#endregion
}
}
2、抽象中介类角色 AbsMediator
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MyMediator
{
//抽象中介类角色AbsMediator
//在这里定义了需要实现的通讯方法
abstract class AbsMediator
{
//在Send方法中,传入的是AbsPeople接口,它是具体People类的基类
public abstract void Send(string message,AbsPeople people);
}
}
3、具体同伴类角色 Student与Teacher
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MyMediator
{
//定义具体同伴类角色
Student类#region Student类
class Student : AbsPeople
{
构造函数#region 构造函数
public Student(AbsMediator mediator)
: base(mediator)
{
}
#endregion
public void Send(string message)
{
mediator.Send(message,this);
}
public void Notify(string message)
{
Console.WriteLine("学生收到信息:{0}",message);
}
}
#endregion
Teacher类#region Teacher类
class Teacher : AbsPeople
{
构造函数#region 构造函数
public Teacher(AbsMediator mediator)
: base(mediator)
{
}
#endregion
public void Send(string message)
{
mediator.Send(message, this);
}
public void Notify(string message)
{
Console.WriteLine("教师收到信息:{0}", message);
}
}
#endregion
}
4、具体中介类角色 RealMediator
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MyMediator
{
class RealMediator: AbsMediator
{
//在Mediator的具体类中融合了所有相关联的People
private Student _pstudent;
private Teacher _pteacher;
public Student PStudent
{
set { _pstudent = value; }
}
public Teacher PB
{
set { _pteacher = value; }
}
public override void Send(string message, AbsPeople people)
{
if(people==_pstudent)
{
_pteacher.Notify(message);
}
if(people==_pteacher)
{
_pstudent.Notify(message);
}
}
}
}
5、客户应用
#region 流程示范
Console.WriteLine("---------------流程示例-------------");
RealMediator rm = new RealMediator();
Student pStudent = new Student(rm);
Teacher pTeacher = new Teacher(rm);
rm.PStudent = pStudent;
rm.PB = pTeacher;
pStudent.Send("老师好");
pTeacher.Send("同学们好.");
Console.ReadKey();
#endregion
二、中介者模式实现的聊天室
1、抽象同伴类角色 AbsParticipant
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MyMediator
{
//定义抽象同伴类角色
//此处定义了两个属性,一个是Name,一个是抽象中介类对象
public abstract class AbsParticipant
{
ChatRoom属性,它是AbsChatRoom类对象#region ChatRoom属性,它是AbsChatRoom类对象
private AbsChatRoom _chatroom;
public AbsChatRoom ChatRoom
{
set { _chatroom = value; }
get { return _chatroom; }
}
#endregion
Name属性#region Name属性
private string _name;
public string Name
{
get { return _name; }
}
#endregion
构造函数#region 构造函数
public AbsParticipant(string name)
{
this._name = name;
}
#endregion
定义其子类需要实现的功能#region 定义其子类需要实现的功能
//在此处功能实现时需要用到抽象中介类对象所具备的功能,如下面的AbsParticipant类Send功能的实现就用到了AbsChatRoom类对象所具备的Send功能。
Send功能#region Send功能
public void Send(string to,string message)
{
_chatroom.Send(_name, to, message); //调用chatroom的Send功能来完成Participant的Send功能,此处的chatroom是一个具体的RealChatRoom
}
#endregion
Receive功能#region Receive功能
public virtual void Receive(string from, string message)
{
Console.WriteLine("{0}to{1}:'{2}'",from,Name,message);
}
#endregion
#endregion
}
}
2、抽象中介类角色 AbsChatRoom
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MyMediator
{
//定义一个抽象类AbsChatRoom,它是RealChatRoom的基类
//此处定义了两个需要实现的功能,一个是注册,一个是发送信息
public abstract class AbsChatRoom
{
public abstract void Register(AbsParticipant participant);
public abstract void Send(string from, string to, string message);
}
}
3、具体同伴类角色 Boy与Girl
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MyMediator
{
//此处定义了两个抽象同伴类角色AbsParticipant的子类,一个是Boy,一个是Girl
男士Partitcipant类#region 男士Partitcipant类
public class Boy:AbsParticipant
{
public Boy(string name)
: base(name)
{
}
public override void Receive(string from, string message)
{
Console.WriteLine("-------{0}听到:----------------", this.Name);
base.Receive(from, message);
}
}
#endregion
女士Participant类#region 女士Participant类
public class Girl : AbsParticipant
{
public Girl(string name)
: base(name)
{
}
public override void Receive(string from, string message)
{
Console.WriteLine("-------{0}听到:----------------",this.Name);
base.Receive(from, message);
}
}
#endregion
}
4、具体中介类角色 RealChatRoom
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MyMediator
{
#region 定义一个具体的ChatRoom,它继承自抽象类AbsChatRoom,并实现AbsChatRoom定义的功能
class RealChatRoom:AbsChatRoom
{
#region 定义一个字典,用于管理参加聊天的人员
private Dictionary<string, AbsParticipant> _participants = new Dictionary<string, AbsParticipant>();
#endregion
#region 实现注册功能
public override void Register(AbsParticipant participant)
{
//如果新加入一个人,他/她不在当前人员列表中,则把此新人加入到列表中
if(!_participants.ContainsValue(participant))
{
_participants[participant.Name] = participant;
}
participant.ChatRoom = this;
}
#endregion
#region 实现发送信息功能
public override void Send(string from, string to, string message)
{
AbsParticipant pt = _participants[to];
if(pt!=null)
{
pt.Receive(from, message); //如果有此人,则调用他/她的Receive方法
}
}
#endregion
}
#endregion
}
5、客户应用
#region 聊天室示例
Console.WriteLine();
Console.WriteLine();
Console.WriteLine("---------------聊天室示例-------------");
RealChatRoom room = new RealChatRoom();
AbsParticipant WangJun = new Boy("王军");
AbsParticipant ZhouQiang = new Boy("周强");
AbsParticipant LiWeiDong = new Boy("李卫东");
AbsParticipant YuanHui = new Boy("袁晖");
AbsParticipant SunLing = new Girl("孙玲");
AbsParticipant DenLiLi = new Girl("邓丽丽");
room.Register(WangJun);
room.Register(ZhouQiang);
room.Register(LiWeiDong);
room.Register(YuanHui);
room.Register(SunLing);
room.Register(DenLiLi);
WangJun.Send("孙玲", "你好孙玲"); //此处实质是调用RealChatRoom定义的Send功能来完成Send操作
ZhouQiang.Send("李卫东", "哥们在吗?");
LiWeiDong.Send("周强", "我才上来,今天工作忙不忙?");
YuanHui.Send("孙玲", "昨天看到你哥了");
SunLing.Send("邓丽丽", "作业做完没有?");
DenLiLi.Send("周强", "你是哪里的?");
Console.ReadKey();
#endregion
程序如下图:
运行效果如下:
适用性:
1.一组对象以定义良好但是复杂的方式进行通信。产生的相互依赖关系结构混乱且难以理解。
2.一个对象引用其他很多对象并且直接与这些对象通信,导致难以复用该对象。
3.想定制一个分布在多个类中的行为,而又不想生成太多的子类。