一、描述
对象类与对象类之间的交互通信统一由另外一个中介类来控制 ,对象通过中介类对其他对象交互,中介类起着控制器的作用。
二、优劣势
优点:降低类与类之间的耦合性,对象与对象之间不再相互引用,把类与类之间的交互抽离出来方便扩展。
缺点:关系过于复杂的话,如对象与对象类交互功能比较多时,中介类将异常庞大,不利于后期维护。
三、需求
实现房东与租客2个人之间的交流,主要有说话和聆听。
四、不使用设计模式
都不考虑设计了,直接撸代码。
3个类,
Person.cs -人基类
Landlord.cs -房东类
Tenant.cs -租客类
// 人基类
public class Person
{
public string name;
public Person(string str)
{
name = str;
}
public virtual void Talk(Person person, string str)
{
}
public virtual void Listen(Person person, string str)
{
}
}
//房东类
public class Landlord : Person
{
public Landlord(string str) : base(str)
{
}
public override void Talk(Person person, string str)
{
Debug.Log("房东-" + name + "发出消息:" + str);
person.Listen(this, str);
}
public override void Listen(Person person, string str)
{
Debug.Log("房东-" + name + "收到来自"+person.name+"的消息:" + str);
}
}
//租客类
public class Tenant : Person
{
public Tenant(string str) : base(str)
{
}
public override void Talk(Person person, string str)
{
Debug.Log("租客-" + name + "发出消息:" + str);
person.Listen(this, str);
}
public override void Listen(Person person, string str)
{
Debug.Log("租客-" + name + "收到来自" + person.name + "的消息:" + str);
}
}
//客户端调用
public static void main(string[] args)
{
Landlord landlord = new Landlord("李姐");
Tenant tenant = new Tenant("小赵");
tenant.Talk(landlord, "房东啊,月租多少?");
landlord.Talk(tenant, "就一千三,很便宜的!");
}
运行结果
小结:每次房东或者租客要说话时,都得把接收者对象传递过去,在说话方法时调用接收对象的listen方法,此处为耦合部分,后续要更改的话不好改。
五、使用设计模式
通过添加一个中介,房东与租客的通话都交给他来处理,这样房东与租客就不需要互相认识再去沟通了。
5个类,
Person.cs -人基类
Landlord.cs -房东类
Tenant.cs -租客类
Mediator -中介者基类
PlayerMediator -中介类实现
// 人基类
public class Person
{
public string name;
protected Mediator mediator;
public Person(string str)
{
name = str;
}
public void SetMediator(Mediator m)
{
mediator = m;
}
public virtual void Talk(string str)
{
}
public virtual void Listen(Person person, string str)
{
}
}
//房东类
public class Landlord : Person
{
public Landlord(string str) : base(str)
{
}
public override void Talk(string str)
{
Debug.Log("房东-" + name + "发出消息:" + str);
mediator.Talk(this,str);
}
public override void Listen(Person person, string str)
{
Debug.Log("房东-" + name + "收到来自" + person.name + "的消息:" + str);
}
}
//租客类
public class Tenant : Person
{
public Tenant(string str) : base(str)
{
}
public override void Talk(string str)
{
Debug.Log("租客-" + name + "发出消息:" + str);
mediator.Talk(this, str);
}
public override void Listen(Person person, string str)
{
Debug.Log("租客-" + name + "收到来自" + person.name + "的消息:" + str);
}
}
//中介基类
public abstract class Mediator
{
public abstract void Talk(Person person, string str);
}
//中介者具体实现
public class PlayerMediator : Mediator
{
private Tenant tenant;//租客
private Landlord landlord;//房东
public void SetTenant(Tenant t)
{
tenant = t;
}
public void SetLandlord(Landlord l)
{
landlord = l;
}
//根据传过来的对象来决定接收者
public override void Talk(Person person, string str)
{
if (person== tenant)
{
landlord.Listen(person,str);
}
else if (person == landlord)
{
tenant.Listen(person, str);
}
}
}
//客户端调用
public static void main(string[] args)
{
Landlord landlord = new Landlord("李姐");
Tenant tenant = new Tenant("小赵");
PlayerMediator playerMediator = new PlayerMediator();
playerMediator.SetLandlord(landlord);
playerMediator.SetTenant(tenant);
landlord.SetMediator(playerMediator);
tenant.SetMediator(playerMediator);
tenant.Talk("房东啊,月租多少?");
landlord.Talk("就一千三,很便宜的!");
}
运行结果
小结:房东与租客在说话时不需要在他talk里去处理调用接收者的listent方法了,而是由其持有的中介对象PlayerMediator去处理这些事,解耦步骤就在这点上,剥离了与接收者的listent通信,虽然客户端调用的步骤多了一些赋值步骤,但是面向对象就是这样, 不要介意这个,还是很稳的放心。
六、设计图
通过学习,我们了解到了中介者模式的应用,我们把刚刚的实现方式画出来。
七、进阶例子
(1)需求:班长通知消息给每一个同学。
(2)分析:按照笨方法,班长得走到每一个人面前跟他说一遍,有几个人就得说几次,也就是班长类得调用无数次talk方法然后依次传入每一个同学类对象,当不只是班长发言,假如2个同学要说悄悄话了,那么就变成了这样:,如下图。
为了解决这个问题,我们引入了交流工具QQ,变成如下:
这样是不是清晰多了,这里的QQ就是我们的中介对象。
(3)实现代码:
5个类,
Student.cs -学生基类
BanZhang.cs -班长类
TongXue.cs -学生类
Mediator -中介者基类
QQMediator -中介QQ类实现
// 学生基类
public class Student
{
public string name;
//中介者qq对象
protected Mediator mediator;
public Student(string str)
{
name = str;
}
public void SetMediator(Mediator m)
{
mediator = m;
}
//在群里说话
public virtual void TalkAll(string str)
{
mediator.TalkAll(this, str);
}
//跟一个人私聊,参数为私聊对象
public virtual void TalkOne(Student student, string str)
{
mediator.TalkOne(this, student, str);
}
public virtual void Listen(Student student, string str)
{
Debug.Log(name + "接收到了来自" + student.name + "的消息:" + str);
}
}
//班长类
public class BanZhang : Student
{
public BanZhang(string str) : base(str)
{
}
}
//同学类
public class TongXue : Student
{
public TongXue(string str) : base(str)
{
}
}
//中介基类
public abstract class Mediator
{
//私聊
public abstract void TalkOne(Student talkMan, Student listentMan, string str);
//群聊
public abstract void TalkAll(Student talkMan, string str);
}
//中介者QQ具体实现
public class QQMediator : Mediator
{
//保存有参与进来qq的人员
private List<Student> studentList;
public QQMediator()
{
studentList = new List<Student>();
}
//添加人员到qq
public void AddStudent(params Student[] s)
{
studentList.AddRange(s);
}
//群聊
public override void TalkAll(Student talkMan, string str)
{
if (studentList.Contains(talkMan))
{
foreach (Student item in studentList)
{
if (item != talkMan)
{
item.Listen(talkMan, str);
}
}
}
}
//私聊
public override void TalkOne(Student talkMan, Student listentMan, string str)
{
if (studentList.Contains(talkMan) && studentList.Contains(listentMan))
{
listentMan.Listen(talkMan,str);
}
}
}
//客户端调用
public static void main(string[] args)
{
QQMediator qqediator = new QQMediator();
BanZhang banZhang = new BanZhang("班长");
banZhang.SetMediator(qqediator);
TongXue tongXue1 = new TongXue("张无忌");
tongXue1.SetMediator(qqediator);
TongXue tongXue2 = new TongXue("赵敏");
tongXue2.SetMediator(qqediator);
qqediator.AddStudent(banZhang, tongXue1, tongXue2);
//班长广播通知消息
banZhang.TalkAll("下午第三节课上体育!");
//也可以这么调用: qqediator.TalkAll(banZhang, "下午第三节课上体育!");
Debug.Log("----------------------分割线----------------------");
//私聊
tongXue1.TalkOne(tongXue2, "小敏,体育课跟我玩吧");
tongXue2.TalkOne(tongXue1, "好的哦");
//也可以这么调用: tongXue2.TalkOne(tongXue1,tongXue2, "下午第三节课上体育!");
}
运行结果:
八、总结
觉得有用就留下评论吧^-^