定义
中介者模式(Mediator)也称调停者模式,是一种比较简单的模式。
英文:Define an object that encapsulates how a set of objects interact.Mediator promotes loose coupling by keeping objects from referring to each other explicitly,and it lets you vary their interaction independently.
翻译:用一个中介者对象封装一系列对象(同事)的交互,中介者使各对象不需要显示的相互作用,从而使其耦合松散,而且中介者可以独立地改变它们之间的交互。
角色:
抽象中介者(Mediator)角色:该角色定义出同事对象到中介者对象的同一接口,用于各同事角色之间的通信。
具体中介者(Concrete Mediator)角色:该角色实现抽象中介者,它依赖于各个同事角色,并通过协调各同事角色实现协作行为。
抽象同事(Colleague)角色:该角色定义出中介者到同事对象的接口,同事对象只知道中介者而不知道其余的同事对象。
具体同事(Concrete Colleague)角色:该角色实现抽象同事类,每一个具体同事类都清楚自己在小范围内的行为,而不知道大范围内的目的。
/** * 抽象中介者模式 */ public abstract class Mediator { //中介者模式的业务逻辑方法,使封装的对象不用显示的相互作用 public abstract void colleagueChanged(Colleague colleague); } /** * 具体中介者 */ public class ConcreteMediator extends Mediator{ private ConcreteColleague1 c1; private ConcreteColleague2 c2; //中介者模式的业务逻辑方法,使封装的对象不用显示的相互作用 public void colleagueChanged(Colleague c){ c1.action(); c2.action(); } //工厂方法,创建同事对象 public void createConcreteMediator(){ c1 = new ConcreteColleague1(this); c2 = new ConcreteColleague2(this); } //获取同事对象 public ConcreteColleague1 getC1(){ return c1; } //获取同事对象 public ConcreteColleague2 getC2(){ return c2; } } /** * 抽象同事类 */ public abstract class Colleague { private Mediator mediator; //因为需要调用中介者的方法,所以要把中介者传进来.如果是中介者方法为静态方法则不必要 //构造函数 public Colleague(Mediator mediator) { this.mediator = mediator; } //getter和setter方法 public Mediator getMediator() { return mediator; } public void setMediator(Mediator mediator) { this.mediator = mediator; } //抽象行动方法,由子类实现 public abstract void action(); //核心业务方法.这个方法看似是本对象和其他对象交互,其实是调用中介者的方法,把自己作为方法参数.委托中介者完成功能 public void change(){ this.mediator.colleagueChanged(this); } } /** * 具体同事类1 */ public class ConcreteColleague1 extends Colleague { //构造函数 public ConcreteColleague1(Mediator mediator) { super(mediator); } @Override public void action() { System.out.println("这是同事1的行动方法!"); } } /** * 具体同事类2 */ public class ConcreteColleague2 extends Colleague { public ConcreteColleague2(Mediator mediator) { super(mediator); } @Override public void action() { System.out.println("这是具体同事类2的方法!"); } }
优点
- 减少类间的依赖。将类之间原有的一对多的依赖变成一对一的依赖,使得对象之间的关系更易理解和维护。
- 避免同事对象之间的过度耦合。同事类只依赖于中介者,这使同事类更易被复用,中介类和同事类可以相对独立地演化。
- 中介者模式将对象的行为和对象间的协作抽象化,将对象在小尺度的行为上与其他对象的相互作用分开处理。
缺点
- 中介者模式降低了同事对象的复杂性,但增加了中介者类的复杂性。
- 中介者类经常充满了各个具体同事类的关系协调代码,这种代码是不可复用的。
注意事项
中介者模式简单,但是简单不代表容易使用,它很容易被误用和滥用。在面向对象的编程中,对象和对象之间必然会有依赖关系,如果某个类和其他类之间没有任何依赖关系,那这个类就是一座孤岛,它在系统中没有存在的必要。一个类依赖多个类的情况是正常的,存在就有其合理性,但并不是只要有多个依赖关系就考虑使用中介者模式。在下列情况不适合使用中介者模式:
- 中介者模式不应当在责任划分混乱时使用。通常的情况下,当一个初级设计师对面向对象的技术不熟悉时,会使一个系统在责任的分割上发生混乱。责任分割的混乱会使得系统中的对象与对象之间产生不适当的复杂关系。
- 中介者模式不应当对数据类和方法类使用。初级设计师常常会设计出这样一中系统:让一系列类只含有数据,另一些类只含有方法。
- 正确理解封装类。封装首先是行为,其次是行为所涉及的状态。行为与状态是不应当分割开来的。中介者模式用来管理很多对象的相互作用,以便使这些对象可以专注于自身的行为。
/** * 婚姻中介所接口 */ public interface MarriageAgency { void pair(Person person); //为person配对 void register(Person person); //注册会员 } /** * 中介所实现类 */ public class MarriageAgencyImpl implements MarriageAgency{ List<Man> men = new ArrayList<Man>(); //男会员 List<Woman> women = new ArrayList<Woman>(); //女会员 @Override public void pair(Person person) { if (person.sex == Sex.MALE){ for (Woman w:women){ if (w.age == person.requestAge){ System.out.println(person.name+"和"+w.name+"配对成功!"); return; } } }else if(person.sex == Sex.FEMALE){ for (Man m:men){ if (m.age == person.requestAge){ System.out.println(person.name+"和"+m.name+"配对成功!"); } } } System.out.println("未找到合适人选!!!"); } @Override public void register(Person person) { if (person.sex == Sex.MALE){ men.add((Man) person); }else if (person.sex == Sex.FEMALE){ women.add((Woman) person); } } } /** * 人抽象类 */ public abstract class Person { String name; //姓名 int age; //年龄 Sex sex; //性别 int requestAge; //要求对象的年龄.对对象 Person requestPerson; MarriageAgency agency; //婚姻中介 public Person(String name, int age, Sex sex, int requestAge, MarriageAgency agency) { this.name = name; this.age = age; this.sex = sex; this.requestAge = requestAge; this.agency = agency; agency.register(this); //注册会员,将自己注册到中介所中 } public void findPartner(){ //寻找对象 agency.pair(this); //根据自己的数据(obj.requestPerson)查找 } } /** * 性别枚举 */ enum Sex { MALE,FEMALE; } /** * 男人类 */ public class Man extends Person{ public Man(String name, int age, int requestAge, MarriageAgency agency) { super(name, age, Sex.MALE, requestAge, agency); } } /** * 女人类 */ public class Woman extends Person{ public Woman(String name, int age, int requestAge, MarriageAgency agency) { super(name, age, Sex.FEMALE, requestAge, agency); } } /** * 测试类 */ public class Main { public static void main(String[] args) { MarriageAgency agency = new MarriageAgencyImpl(); //姓名为allen,27岁的man对象,寻找28岁异性 //agency为中介所,在构造函数中会把自己构造的对象传递到angency中 Person m1 = new Man("allen",27,28,agency); Person m2 = new Man("sywer",25,20,agency); Person w1 = new Woman("catalin",28,23,agency); Person w2 = new Woman("feilicity",25,23,agency); m1.findPartner();
//看似是m1调用查找伴侣方法,其实是调用了agency.find(this),即m1执行此方法调用中介所的find方法,而本身作为一个参数传递过去. m2.findPartner(); } }
个人总结:
1.在实例化同事类的时候,中介者作为构造参数media,并在构造函数中执行media.regist(this)把自己注册到中介者中去。
2.实例化的同事类调用方法(和其他类交互的方法),底层为中介者调用find(this)把自己作为参数,让中介者替自己执行和其他类交互的方法(核心业务,各个类不需要显示调用)。
/** * 中介者-聊天室 */ public class Chat { public static void showMessage(User user,String msg){ System.out.println(new SimpleDateFormat("yyyy-dd-hh-mm-ss").format(new Date())+" "+user.getName()+": "+msg); } } /** * 聊天用户 */ public class User { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public User(String name) { this.name = name; } public void sendMsg(String msg){ Chat.showMessage(this,msg); //中介者静态方法,所以同事类中不需要有中介者对象 } } /** * 测试 */ public class MainDemo { public static void main(String[] args) { User u1 = new User("sywer"); User u2 = new User("catalin"); u1.sendMsg("hello!"); u2.sendMsg("bye"); } }