设计模式--14、中介者模式
定义:用一个中介者对象封装一系列的对象交互,中介者使各对象不需要显示地相互作用,从而使耦合松散,而且可以独立地改变它们之间的交互。
类型:行为类模式
看看结构图的形象描述吧:
中介者模式的结构
中介者模式又称为调停者模式,从类图中看,共分为3部分:
- 抽象中介者:定义好同事类对象到中介者对象的接口,用于各个同事类之间的通信。一般包括一个或几个抽象的事件方法,并由子类去实现。
- 中介者实现类:从抽象中介者继承而来,实现抽象中介者中定义的事件方法。从一个同事类接收消息,然后通过消息影响其他同时类。
- 同事类:如果一个对象会影响其他的对象,同时也会被其他对象影响,那么这两个对象称为同事类。在类图中,同事类只有一个,这其实是现实的省略,在实际应用中,同事类一般由多个组成,他们之间相互影响,相互依赖。同事类越多,关系越复杂。并且,同事类也可以表现为继承了同一个抽象类的一组实现组成。在中介者模式中,同事类之间必须通过中介者才能进行消息传递。
为什么要使用中介者模式
一般来说,同事类之间的关系是比较复杂的,多个同事类之间互相关联时,他们之间的关系会呈现为复杂的网状结构,这是一种过度耦合的架构,即不利于类的复用,也不稳定。例如在下图中,有六个同事类对象,假如对象1发生变化,那么将会有4个对象受到影响。如果对象2发生变化,那么将会有5个对象受到影响。也就是说,同事类之间直接关联的设计是不好的。
如果引入中介者模式,那么同事类之间的关系将变为星型结构,从图中可以看到,任何一个类的变动,只会影响的类本身,以及中介者,这样就减小了系统的耦合。一个好的设计,必定不会把所有的对象关系处理逻辑封装在本类中,而是使用一个专门的类来管理那些不属于自己的行为。
对于设计模式这个东西,理解了,应该写一个代码体会一下,我们以qq和email发送消息为实例,代码如下:
package designpatterns; import java.util.HashMap; import java.util.Map.Entry; /* * 中介者模式 */ //先抽像一个使用者类(学生) abstract class Person { String strName; //姓名 String strType; //类型 //每个人都有一个用来传递信息的中介List,如qq,email等 HashMap<String, AbstractMediator> MyMediatorList = new HashMap<String, AbstractMediator>(); public Person(String strName){ this.strName = strName; } public String getStrName() { return strName; } public void setStrName(String strName) { this.strName = strName; } public String getStrType() { return strType; } public void setStrType(String strType) { this.strType = strType; } public void AddMediator(AbstractMediator MyMediator) { MyMediatorList.put(MyMediator.getStrName(), MyMediator); } //给所有人发消息 public void SendMessageToAll(String MediatorName, String strMessage){ MyMediatorList.get(MediatorName).SendMessageToAll(strMessage); } //给指定类型的人发消息 public void SendMessageByType(String MediatorName, String strType, String strMessage) { MyMediatorList.get(MediatorName).SendMessageByType(strType, strMessage); } //给指定名字的人发消息 public void SendMessageByName(String MediatorName, String strName, String strMessage) { MyMediatorList.get(MediatorName).SendMessageByName(strName, strMessage); } //接收消息 public void ReciveMessage(String strMessage){ System.out.println("[" + strType +"]" + "\"" + strName + "\"" + "收到"+strMessage); } } //定义学生 class Student extends Person { public Student(String strName) { super(strName); strType = "学生"; } } //定义老师 class Teacher extends Person { public Teacher(String strName) { super(strName); strType = "老师"; } } //定义校长 class Principal extends Person { public Principal(String strName) { super(strName); strType = "校长"; } } //定义一个抽象中介 abstract class AbstractMediator { //中介的名字 String strName; public AbstractMediator (String strName) { this.strName = strName; } public String getStrName() { return strName; } //定义一个人员列表 HashMap<String, Person> PersonList = new HashMap<String, Person>(); public void addPerson(Person onePerson) { PersonList.put(onePerson.getStrName(), onePerson); onePerson.AddMediator(this); } public void deletePerson(String strName) { PersonList.remove(strName); } //给所有人发消息 abstract public void SendMessageToAll(String strMessage); //给指定类型的人发消息 abstract public void SendMessageByType(String strType, String strMessage); //给指定名字的人发消息 abstract public void SendMessageByName(String strName, String strMessage); } //定义一个中介(QQ)用于传递消息 class QQMediator extends AbstractMediator{ public QQMediator(String strName) { super(strName); } @Override public void SendMessageToAll(String strMessage) { String strQQMessage = "来自QQ消息:" + strMessage; for(Entry<String, Person> entry : PersonList.entrySet()){ entry.getValue().ReciveMessage(strQQMessage); } } @Override public void SendMessageByType(String strType, String strMessage) { String strQQMessage = "来自QQ消息:" + strMessage; for(Entry<String, Person> entry : PersonList.entrySet()){ if(strType == entry.getValue().getStrType()) { entry.getValue().ReciveMessage(strQQMessage); } } } @Override public void SendMessageByName(String strName, String strMessage) { String strQQMessage = "来自QQ消息:" + strMessage; PersonList.get(strName).ReciveMessage(strQQMessage); } } //定义一个中介(Email)用于传递消息 class EmailMediator extends AbstractMediator{ public EmailMediator(String strName) { super(strName); } @Override public void SendMessageToAll(String strMessage) { String strQQMessage = "来自Email消息:" + strMessage; for(Entry<String, Person> entry : PersonList.entrySet()){ entry.getValue().ReciveMessage(strQQMessage); } } @Override public void SendMessageByType(String strType, String strMessage) { String strQQMessage = "来自Email消息:" + strMessage; for(Entry<String, Person> entry : PersonList.entrySet()){ if(strType == entry.getValue().getStrType()) { entry.getValue().ReciveMessage(strQQMessage); } } } @Override public void SendMessageByName(String strName, String strMessage) { String strQQMessage = "来自Email消息:" + strMessage; PersonList.get(strName).ReciveMessage(strQQMessage); } } public class Mediator { public static void main(String[] args) { //定义两个学生 Student student1 = new Student("学生一"); Student student2 = new Student("学生二"); //定义两个老师 Teacher teacher1 = new Teacher("老师一"); Teacher teacher2 = new Teacher("老师二"); //定义两个校长 Principal principal1 = new Principal("校长一"); Principal principal2 = new Principal("校长二"); //定义两个中介(QQ和email) QQMediator myQQ = new QQMediator("qq"); EmailMediator myEmail = new EmailMediator("email"); //将所有人员分别添加到qq和email中 myQQ.addPerson(student1); myQQ.addPerson(student2); myQQ.addPerson(teacher1); myQQ.addPerson(teacher2); myQQ.addPerson(principal1); myQQ.addPerson(principal2); myEmail.addPerson(student1); myEmail.addPerson(student2); myEmail.addPerson(teacher1); myEmail.addPerson(teacher2); myEmail.addPerson(principal1); myEmail.addPerson(principal2); //下面开始进行通信 //首先"校长一"通过qq向"校长二"发一条消息 principal1.SendMessageByName("qq", "校长二", "你觉得什么时候放假好?"); principal2.SendMessageByName("qq", "校长一", "从明天开始放假吧!"); principal1.SendMessageByName("qq", "校长二", "好的,那我发通知了"); //然后"校长一"通过email向所有人员发一条消息 principal1.SendMessageByType("email", "老师", "老师们都注意了,从明天开始放假"); //老师收到消息后再给学生发消息 teacher1.SendMessageByType("email", "学生", "同学们都注意了,从明天开始放假了!"); //学生收到消息后,开始qq聊起来了 student1.SendMessageByName("qq", "学生二", "明天放假了,我们去哪玩啊?"); student2.SendMessageByName("qq", "学生一", "我们去爬山吧,再问问还有没有别人去!"); student2.SendMessageToAll("email", "明天我们去爬山,还有没有一起去的?"); } }
二、使用中介者模式的场合和优缺点
使用终结者模式的场合
1.一组定义良好的对象,现在要进行复杂的通信。
2.定制一个分布在多个类中的行为,而又不想生成太多的子类。
可以看出,中介对象主要是用来封装行为的,行为的参与者就是那些对象,但是通过中介者,这些对象不用相互知道。呵呵~~~
使用中介者模式的优点:
1.降低了系统对象之间的耦合性,使得对象易于独立的被复用。
2.提高系统的灵活性,使得系统易于扩展和维护。
使用中介者模式的缺点:
中介者模式的缺点是显而易见的,因为这个“中介“承担了较多的责任,所以一旦这个中介对象出现了问题,那么整个系统就会受到重大的影响。