设计模式(16)——中介者模式

来源:互联网 发布:c语言开发实战宝典 编辑:程序博客网 时间:2024/06/16 03:27

中介者模式

中介在现实生活中并不陌生,满大街的房屋中介、良莠不齐的出国中介……。它们的存在是因为它们能给我们的生活带来一些便利:租房、买房用不着各个小区里瞎转;出国留学也不用不知所措。中介者模式在程序设计中也起到了类似的作用.

一、定义

GOF给中介者模式下的定义是:用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。

简单点来说,将原来两个直接引用或者依赖的对象拆开,在中间加入一个“中介”对象,使得两头的对象分别和“中介”对象引用或者依赖。

二、结构

2.1标准的中介者模式类图

2.2包含角色

  • Mediator:中介者接口。在里面定义各个同事对象之间的交互对象,可以是公共的通信方法,比如changed,execute方法,大家都用,也可以是小范围的交互方法。
  • ConcreteMediator:具体中介者实现对象。他需要维护各个同事对象之间的交互关系
  • Colleague:同事类的定义,所有具体同事类的父类,通常实现成抽象类,主要负责约束同事对象的类型,并实现一些具体同事类之间的功能。
  • ConcreteColleague:具体的同事类,实现自己的业务,在需要与其他同事通信的时候,就与持有的中介者通信,中介者负责与其他的同事进行交互。

2.3通用代码

为什么同事类要使用构造函数注入中介者而中介者使用getter/setter方式注入同事类呢?想过没有?那是因为同事类必须有中介者,而中介者可以只有部分同事类。

Mediator类

[java] view plaincopyprint?
  1. public abstract class Mediator {  
  2.     // 定义同事类  
  3.     protected ConcreteColleague1 c1;  
  4.     protected ConcreteColleague2 c2;  
  5.   
  6.     // 通过getter/setter方法把同事类注入进来  
  7.     public ConcreteColleague1 getC1() {  
  8.         return c1;  
  9.   
  10.     }  
  11.   
  12.     public void setC1(ConcreteColleague1 c1) {  
  13.         this.c1 = c1;  
  14.     }  
  15.   
  16.     public ConcreteColleague2 getC2() {  
  17.         return c2;  
  18.     }  
  19.   
  20.     public void setC2(ConcreteColleague2 c2) {  
  21.         this.c2 = c2;  
  22.     }  
  23.   
  24.     // 中介者模式的业务逻辑  
  25.     public abstract void doSomething1();  
  26.   
  27.     public abstract void doSomething2();  
  28. }  

具体的中介者一般只有一个

[java] view plaincopyprint?
  1. public class ConcreteMediator extends Mediator {  
  2.     @Override  
  3.     public void doSomething1() {  
  4.         // 调用同事类的方法,只要是public方法都可以调用  
  5.         super.c1.selfMethod1();  
  6.         super.c2.selfMethod2();  
  7.     }  
  8.   
  9.     public void doSomething2() {  
  10.         super.c1.selfMethod1();  
  11.         super.c2.selfMethod2();  
  12.     }  
  13. }  

同事类的基类(含有中介者的引用)

[html] view plaincopyprint?
  1. public abstract class Colleague {  
  2.     protected Mediator mediator;  
  3.   
  4.     public Colleague(Mediator _mediator) {  
  5.         this.mediator = _mediator;  
  6.     }  
  7. }  

同事实现类ConcreteColleague1

[java] view plaincopyprint?
  1. public class ConcreteColleague1 extends Colleague {  
  2.     // 通过构造函数传递中介者  
  3.     public ConcreteColleague1(Mediator _mediator) {  
  4.         super(_mediator);  
  5.     }  
  6.   
  7.     // 自有方法 self-method  
  8.     public void selfMethod1() {  
  9.         // 处理自己的业务逻辑  
  10.     }  
  11.   
  12.     // 依赖方法dep-method  
  13.     public void depMethod1() {  
  14.         // 处理自己的业务逻辑  
  15.         // 自己不能处理的业务逻辑,委托给中介者处理  
  16.         super.mediator.doSomething1();  
  17.     }  
  18. }  

同事实现类ConcreteColleague2

[java] view plaincopyprint?
  1. public class ConcreteColleague2 extends Colleague {  
  2.     // 通过构造函数传递中介者  
  3.     public ConcreteColleague2(Mediator _mediator) {  
  4.         super(_mediator);  
  5.   
  6.     }  
  7.   
  8.     // 自有方法 self-method  
  9.     public void selfMethod2() {  
  10.         // 处理自己的业务逻辑  
  11.     }  
  12.   
  13.     // 依赖方法dep-method  
  14.     public void depMethod2() {  
  15.         // 处理自己的业务逻辑  
  16.         // 自己不能处理的业务逻辑,委托给中介者处理  
  17.         super.mediator.doSomething2();  
  18.     }  
  19. }  

三、进销存管理例子

影响

采购

销售

存货

采购

 

畅销就多采购,滞销就不采购;

库房是有容积限制的

销售

销售时,库存容量不够,督促采购

 

销售要考虑存货情况,库房有货,才能销售,

存货

清仓处理时要求采购部门别采购

清仓时打折销售

 

类图(具体代码参见 设计模式之禅 中介者模式)

这三个类间是彼此关联的,每个类都与其他两个类产生了关联关系,迪米特法则教育我们“每个类只和朋友类交流”,这个朋友类可不是越多越好,越多耦合性越大,改一个对象而要修改一片对象,这可不是面向对象设计所期望的,而且这还是就三个模块的情况,比较简单的一个小项目,如果有十个八个这样的模块,如下图的情况,就成了蜘蛛网结构,太复杂了

引入中介者模式解决

加入了一个中介者作为三个模块的交流核心,每个模块之间不再相互交流,要交流就通过中介者进行,每个模块只负责自己的业务逻辑,不属于自己的则丢给中介者来处理,看类图:

建立了两个抽象类AbstractMediator和AbstractColeague,每个对象只是与中介者Mediator之间产生依赖,与其他对象之间没有直接的关系,AbstractMediator的作用是把中介者的抽象定义,定义了一个抽象方法execute,

AbstractMediator

[java] view plaincopyprint?
  1. public abstract class AbstractMediator {  
  2.     protected Purchase purchase;  
  3.     protected Sale sale;  
  4.     protected Stock stock;  
  5.   
  6.     // 构造函数  
  7.     public AbstractMediator() {  
  8.         purchase = new Purchase(this);  
  9.         sale = new Sale(this);  
  10.         stock = new Stock(this);  
  11.     }  
  12.   
  13.     // 中介者最重要的方法,叫做事件方法,处理多个对象之间的关系  
  14.     public abstract void execute(String str, Object... objects);  
  15. }  

具体的中介

[java] view plaincopyprint?
  1. public class Mediator extends AbstractMediator {  
  2.     // 中介者最重要的方法  
  3.     public void execute(String str, Object... objects) {  
  4.         if (str.equals("purchase.buy")) { // 采购电脑  
  5.             this.buyComputer((Integer) objects[0]);  
  6.         } else if (str.equals("sale.sell")) { // 销售电脑  
  7.             this.sellComputer((Integer) objects[0]);  
  8.         } else if (str.equals("sale.offsell")) { // 折价销售  
  9.             this.offSell();  
  10.         } else if (str.equals("stock.clear")) { // 清仓处理  
  11.             this.clearStock();  
  12.         }  
  13.     }  
  14.   
  15.     // 采购电脑  
  16.     private void buyComputer(int number) {  
  17.         int saleStatus = super.sale.getSaleStatus();  
  18.         if (saleStatus > 80) { // 销售情况良好  
  19.             System.out.println("采购IBM电脑:" + number + "台");  
  20.             super.stock.increase(number);  
  21.         } else { // 销售情况不好  
  22.             int buyNumber = number / 2// 折半采购  
  23.             System.out.println("采购IBM电脑:" + buyNumber + "台");  
  24.         }  
  25.     }  
  26.   
  27.     // 销售电脑  
  28.     private void sellComputer(int number) {  
  29.         if (super.stock.getStockNumber() < number) { // 库存数量不够销售  
  30.             super.purchase.buyIBMcomputer(number);  
  31.         }  
  32.         super.stock.decrease(number);  
  33.     }  
  34.   
  35.     // 折价销售电脑  
  36.     private void offSell() {  
  37.         System.out.println("折价销售IBM电脑" + stock.getStockNumber() + "台");  
  38.     }  
  39.   
  40.     // 清仓处理  
  41.     private void clearStock() {  
  42.         // 要求清仓销售  
  43.         super.sale.offSale();  
  44.         // 要求采购人员不要采购  
  45.         super.purchase.refuseBuyIBM();  
  46.     }  
  47. }  

AbstractColleague

[java] view plaincopyprint?
  1. public abstract class AbstractColleague {  
  2.     protected AbstractMediator mediator;  
  3.   
  4.     public AbstractColleague(AbstractMediator _mediator) {  
  5.         this.mediator = _mediator;  
  6.     }  
  7. }  

采购类Purchase

[java] view plaincopyprint?
  1. public class Purchase extends AbstractColleague {  
  2.     public Purchase(AbstractMediator _mediator) {  
  3.         super(_mediator);  
  4.     }  
  5.   
  6.     // 采购IBM型号的电脑  
  7.     public void buyIBMcomputer(int number) {  
  8.         super.mediator.execute("purchase.buy", number);  
  9.     }  
  10.   
  11.     // 不在采购IBM电脑  
  12.     public void refuseBuyIBM() {  
  13.         System.out.println("不再采购IBM电脑");  
  14.     }  
  15. }  

Stock类

[java] view plaincopyprint?
  1. public class Stock extends AbstractColleague {  
  2.     public Stock(AbstractMediator _mediator) {  
  3.         super(_mediator);  
  4.     }  
  5.   
  6.     // 刚开始有100台电脑  
  7.     private static int COMPUTER_NUMBER = 100;  
  8.   
  9.     // 库存增加  
  10.     public void increase(int number) {  
  11.         COMPUTER_NUMBER = COMPUTER_NUMBER + number;  
  12.         System.out.println("库存数量为:" + COMPUTER_NUMBER);  
  13.     }  
  14.   
  15.     // 库存降低  
  16.     public void decrease(int number) {  
  17.         COMPUTER_NUMBER = COMPUTER_NUMBER - number;  
  18.         System.out.println("库存数量为:" + COMPUTER_NUMBER);  
  19.     }  
  20.   
  21.     // 获得库存数量  
  22.     public int getStockNumber() {  
  23.         return COMPUTER_NUMBER;  
  24.     }  
  25.   
  26.     // 存货压力大了,就要通知采购人员不要采购,销售人员要尽快销售  
  27.     public void clearStock() {  
  28.         System.out.println("清理存货数量为:" + COMPUTER_NUMBER);  
  29.         super.mediator.execute("stock.clear");  
  30.     }  
  31. }  

Sale类

[java] view plaincopyprint?
  1. import java.util.Random;  
  2.   
  3. public class Sale extends AbstractColleague {  
  4.     public Sale(AbstractMediator _mediator) {  
  5.         super(_mediator);  
  6.     }  
  7.   
  8.     // 销售IBM型号的电脑  
  9.     public void sellIBMComputer(int number) {  
  10.         super.mediator.execute("sale.sell", number);  
  11.         System.out.println("销售IBM电脑" + number + "台");  
  12.     }  
  13.   
  14.     // 反馈销售情况,0——100之间变化,0代表根本就没人卖,100代表非常畅销,出1一个卖一个  
  15.     public int getSaleStatus() {  
  16.         Random rand = new Random(System.currentTimeMillis());  
  17.         int saleStatus = rand.nextInt(100);  
  18.         System.out.println("IBM电脑的销售情况为:" + saleStatus);  
  19.         return saleStatus;  
  20.     }  
  21.   
  22.     // 折价处理  
  23.     public void offSale() {  
  24.         super.mediator.execute("sale.offsell");  
  25.     }  
  26. }  

场景类

[java] view plaincopyprint?
  1. public class Client {  
  2.     public static void main(String[] args) {  
  3.         AbstractMediator mediator = new Mediator();  
  4.         // 采购人员采购电脑  
  5.         System.out.println("------采购人员采购电脑--------");  
  6.         Purchase purchase = new Purchase(mediator);  
  7.         purchase.buyIBMcomputer(100);  
  8.         // 销售人员销售电脑  
  9.         System.out.println("\n------销售人员销售电脑--------");  
  10.         Sale sale = new Sale(mediator);  
  11.         sale.sellIBMComputer(1);  
  12.         // 库房管理人员管理库存  
  13.         System.out.println("\n------库房管理人员清库处理--------");  
  14.         Stock stock = new Stock(mediator);  
  15.         stock.clearStock();  
  16.     }  
  17. }  

在场景类中增加了一个中介者,然后分别传递到三个同事类中,三个类都具有相同的特性:只负责处理自己的活动(行为),与自己无关的活动就丢给中介者处理,程序运行的结果是相同的。从项目设计上来看,加入了中介者,设计结构清晰了很多,而且类间的耦合性大大减少,代码质量也有了很大的提升。

运行结果

------采购人员采购电脑--------
IBM电脑的销售情况为:34
采购IBM电脑:50台

------销售人员销售电脑--------
库存数量为:99
销售IBM电脑1台

------库房管理人员清库处理--------
清理存货数量为:99
折价销售IBM电脑99台
不再采购IBM电脑

 

四、部门人员例子

1:部门与人员

几乎在每个应用系统中都需要这样的功能模块:部门管理、人员管理,为了简单点演示,把模块简化成类,也就是有一个部门类Dep和人员类User。

   首先想想部门类Dep和人员类User之间是什么关系,一对一?一对多?还是多对多?从实际情况讲,部门和人员应该是多对多的,也就是一个部门可以有多个人,而一个人也可以加入多个部门。不就是个多对多吗,类之间的多对多也很容易表达啊,如下:

Dep

[java] view plaincopyprint?
  1. public class Dep {  
  2.   
  3.     private List<User> colUser = new ArrayList<User>();  
  4.   
  5. }  

User

[java] view plaincopyprint?
  1. public class User {  
  2.   
  3.     private List<Dep> colDep = new ArrayList<Dep>();  
  4.   
  5. }  

很简单,是吧,一个部门有多个人员,一个人员属于多个部门。

2:问题的出现

    真的这么简单吗?再进一步想想部门和人员的功能交互,就会知道这样设计是存在问题的,举几个常见的功能:

  • 部门被撤销
  • 部门之间进行合并
  • 人员离职
  • 人员从一个部门调职到另外一个部门

想想要实现这些功能,按照前面的设计,该怎么做呢?

(1)系统运行期间,部门被撤销了,就意味着这个部门不存在了,可是原来这个部门下所有的人员,每个人员的所属部门中都有这个部门呢,那么就需要先通知所有的人员,把这个部门从它们的所属部门中去掉,然后才可以清除这个部门。

(2)部门合并,是合并成一个新的部门呢,还是把一个部门并入到另一个部门?如果是合并成一个新的部门,那么需要把原有的两个部门撤销,然后再新增一个部门;如果是把一个部门合并到另一个部门里面,那就是撤销掉一个部门,然后把这个部门下的人员移动到这个部门。不管是那种情况,都面临着需要通知相应的人员进行更改这样的问题。

(3)人员离职了,反过来就需要通知他所属于的部门,从部门的拥有人员的记录中去除掉这个人员。

(4)人员调职,同样需要通知相关的部门,先从原来的部门中去除掉,然后再到新的部门中添加上。

看了上述的描述,感觉如何?是不是“烦就一个字”啊!

麻烦的根源在什么地方呢?仔细想想,对了,麻烦的根源就在于部门和人员之间的耦合,这样导致操作人员的时候,需要操作所有相关的部门,而操作部门的时候又需要操作所有相关的人员,使得部门和人员搅和在了一起。

3:中介者来解决

找到了根源就好办了,采用中介者模式,引入一个中介者对象来管理部门和人员之间的关系,就能解决这些问题了。

如果采用标准的中介者模式,想想上面提出的那些问题点吧,就知道实现起来会很别扭。因此采用广义的中介者来解决,这样部门和人员就完全解耦了,也就是说部门不知道人员,人员也不知道部门,它们完全分开,它们之间的关系就完全由中介者对象来管理了。这个时候的结构如图所示:

 

 

图、引入中介者后的结构示意图

代码如下:

User

[java] view plaincopyprint?
  1. public class User {  
  2.   
  3.     private String userId;  
  4.     private String userName;  
  5.   
  6.     /** 
  7.      * 人员离职 
  8.      * @return 
  9.      */  
  10.     public boolean dimission() {  
  11.         DepUserMediatorImpl mediator = DepUserMediatorImpl.getInstance();  
  12.         mediator.deleteUser(userId);  
  13.         return true;  
  14.     }  
  15.   
  16.     //Getter 和 Setter  
  17.     public String getUserId() {  
  18.         return userId;  
  19.     }  
  20.   
  21.     public void setUserId(String userId) {  
  22.         this.userId = userId;  
  23.     }  
  24.   
  25.     public String getUserName() {  
  26.         return userName;  
  27.     }  
  28.   
  29.     public void setUserName(String userName) {  
  30.         this.userName = userName;  
  31.     }  
  32.   
  33.       
  34. }  

Dep

[java] view plaincopyprint?
  1. /** 
  2.  * 部门类 
  3.  */  
  4. public class Dep {  
  5.   
  6.     private String depId;  
  7.     private String depName;  
  8.   
  9.     /** 
  10.      * 撤销部门 
  11.      * @return 
  12.      */  
  13.     public boolean deleteDep() {  
  14.         DepUserMediatorImpl mediator = DepUserMediatorImpl.getInstance();  
  15.         mediator.deleteDep(depId);  
  16.         return true;  
  17.     }  
  18.   
  19.     public String getDepId() {  
  20.         return depId;  
  21.     }  
  22.   
  23.     public void setDepId(String depId) {  
  24.         this.depId = depId;  
  25.     }  
  26.   
  27.     public String getDepName() {  
  28.         return depName;  
  29.     }  
  30.   
  31.     public void setDepName(String depName) {  
  32.         this.depName = depName;  
  33.     }  
  34. }  

DepUserModel 描述部门与人员关系

[java] view plaincopyprint?
  1. /** 
  2.  * 描述部门与人员关系的类 
  3.  * 
  4.  */  
  5. public class DepUserModel {  
  6.   
  7.     private String depUserId;  
  8.     private String depId;  
  9.     private String userId;  
  10.     public String getDepUserId() {  
  11.         return depUserId;  
  12.     }  
  13.     public void setDepUserId(String depUserId) {  
  14.         this.depUserId = depUserId;  
  15.     }  
  16.     public String getDepId() {  
  17.         return depId;  
  18.     }  
  19.     public void setDepId(String depId) {  
  20.         this.depId = depId;  
  21.     }  
  22.     public String getUserId() {  
  23.         return userId;  
  24.     }  
  25.     public void setUserId(String userId) {  
  26.         this.userId = userId;  
  27.     }  
  28.   
  29.   
  30. }  

DepUserMediatorImpl 实现部门和人员交互的中介者

[java] view plaincopyprint?
  1. import java.util.ArrayList;  
  2. import java.util.List;  
  3.   
  4. /** 
  5.  * 实现部门和人员交互的中介者实现类 
  6.  */  
  7. public class DepUserMediatorImpl {  
  8.   
  9.     private static DepUserMediatorImpl mediator = new DepUserMediatorImpl();  
  10.   
  11.     private DepUserMediatorImpl() {  
  12.         initTestData();  
  13.     }  
  14.   
  15.     public static DepUserMediatorImpl getInstance() {  
  16.         return mediator;  
  17.     }  
  18.   
  19.     /** 
  20.      * 记录部门和人员关系 
  21.      */  
  22.     private final List<DepUserModel> depUserCol = new ArrayList<DepUserModel>();  
  23.   
  24.     /** 
  25.      * 初始化测试数据 
  26.      */  
  27.     private void initTestData() {  
  28.         DepUserModel du1 = new DepUserModel();  
  29.         du1.setDepUserId("du1");  
  30.         du1.setDepId("d1");  
  31.         du1.setUserId("u1");  
  32.         depUserCol.add(du1);  
  33.   
  34.         DepUserModel du2 = new DepUserModel();  
  35.         du2.setDepUserId("du2");  
  36.         du2.setDepId("d1");  
  37.         du2.setUserId("u2");  
  38.         depUserCol.add(du2);  
  39.   
  40.         DepUserModel du3 = new DepUserModel();  
  41.         du3.setDepUserId("du3");  
  42.         du3.setDepId("d2");  
  43.         du3.setUserId("u3");  
  44.         depUserCol.add(du3);  
  45.   
  46.         DepUserModel du4 = new DepUserModel();  
  47.         du4.setDepUserId("du4");  
  48.         du4.setDepId("d2");  
  49.         du4.setUserId("u4");  
  50.         depUserCol.add(du4);  
  51.   
  52.         DepUserModel du5 = new DepUserModel();  
  53.         du5.setDepUserId("du5");  
  54.         du5.setDepId("d2");  
  55.         du5.setUserId("u1");  
  56.         depUserCol.add(du5);  
  57.     }  
  58.   
  59.     /** 
  60.      * 当部门被撤销时,应删去部门与该部门中人员的关系 
  61.      *  
  62.      * @param depId 
  63.      *            被撤销部门的编号 
  64.      * @return 
  65.      */  
  66.     public boolean deleteDep(String depId) {  
  67.         List<DepUserModel> tempCol = new ArrayList<DepUserModel>();  
  68.         for (DepUserModel du : depUserCol) {  
  69.             if (du.getDepId().equals(depId)) {  
  70.                 tempCol.add(du);  
  71.             }  
  72.         }  
  73.         depUserCol.removeAll(tempCol);  
  74.         return true;  
  75.     }  
  76.   
  77.     /** 
  78.      * 当人员离职时,应删去该人员与所在部门的关系 
  79.      *  
  80.      * @param userId 
  81.      *            离职人员的编号 
  82.      * @return 
  83.      */  
  84.     public boolean deleteUser(String userId) {  
  85.         List<DepUserModel> tempCol = new ArrayList<DepUserModel>();  
  86.         for (DepUserModel du : depUserCol) {  
  87.             if (du.getUserId().equals(userId)) {  
  88.                 tempCol.add(du);  
  89.             }  
  90.         }  
  91.         depUserCol.removeAll(tempCol);  
  92.         return true;  
  93.     }  
  94.   
  95.     /** 
  96.      * 显示部门中的所有人员 
  97.      *  
  98.      * @param dep 
  99.      *            部门对象 
  100.      */  
  101.     public void showDepUser(Dep dep) {  
  102.         for (DepUserModel du : depUserCol) {  
  103.             if (du.getDepId().equals(dep.getDepId())) {  
  104.                 System.out.println("部门编号=" + dep.getDepId() + "下面拥有人员,其编号是:"  
  105.                         + du.getUserId());  
  106.             }  
  107.         }  
  108.     }  
  109.   
  110.     /** 
  111.      * 显示人员所在的部门 
  112.      *  
  113.      * @param user 
  114.      *            人员对象 
  115.      */  
  116.     public void showUserDeps(User user) {  
  117.         for (DepUserModel du : depUserCol) {  
  118.             if (du.getUserId().equals(user.getUserId())) {  
  119.                 System.out.println("人员编号=" + user.getUserId() + "属于部门编号是:"  
  120.                         + du.getDepId());  
  121.             }  
  122.         }  
  123.     }  
  124.   
  125.     /** 
  126.      * 完成因人员调换部门引起的与部门的交互 
  127.      *  
  128.      * @param userId 
  129.      *            被调换的人员的编号 
  130.      * @param oldDepId 
  131.      *            调换前的部门编号 
  132.      * @param newDepId 
  133.      *            调换后的部门编号 
  134.      * @return 
  135.      */  
  136.     public boolean changeDep(String userId, String oldDepId, String newDepId) {  
  137.         // 本示例就不是实现了  
  138.         return false;  
  139.     }  
  140.   
  141.     /** 
  142.      * 因部门合并所引起的与人员的交互 
  143.      *  
  144.      * @param colDepIds 
  145.      *            需要被合并的部门编号 
  146.      * @param newDep 
  147.      *            合并后部门的编号 
  148.      * @return 
  149.      */  
  150.     public boolean joinDep(List<String> colDepIds, Dep newDep) {  
  151.         // 本示例就不是实现了  
  152.         return false;  
  153.     }  
  154. }  

场景类

[java] view plaincopyprint?
  1. public class Client {  
  2.   
  3.     public static void main(String[] args) {  
  4.         DepUserMediatorImpl mediator = DepUserMediatorImpl.getInstance();  
  5.   
  6.         Dep dep = new Dep();  
  7.         dep.setDepId("d1");  
  8.         Dep dep2 = new Dep();  
  9.         dep2.setDepId("d2");  
  10.   
  11.         User user = new User();  
  12.         user.setUserId("u1");  
  13.   
  14.         System.out.println("撤销部门前----------------------------------------");  
  15.         mediator.showUserDeps(user);  
  16.         // 撤销部门  
  17.         dep.deleteDep();  
  18.         System.out.println("撤销部门后----------------------------------------");  
  19.         mediator.showUserDeps(user);  
  20.   
  21.         System.out.println("----------------------------------------");  
  22.         System.out.println("人员离职前----------------------------------------");  
  23.         mediator.showDepUser(dep2);  
  24.         // 人员离职  
  25.         user.dimission();  
  26.         System.out.println("人员离职后----------------------------------------");  
  27.         mediator.showDepUser(dep2);  
  28.     }  
  29. }  

执行结果

撤销部门前----------------------------------------
人员编号=u1属于部门编号是:d1
人员编号=u1属于部门编号是:d2
撤销部门后----------------------------------------
人员编号=u1属于部门编号是:d2
----------------------------------------
人员离职前----------------------------------------
部门编号=d2下面拥有人员,其编号是:u3
部门编号=d2下面拥有人员,其编号是:u4
部门编号=d2下面拥有人员,其编号是:u1
人员离职后----------------------------------------
部门编号=d2下面拥有人员,其编号是:u3
部门编号=d2下面拥有人员,其编号是:u4

 

五、发送接收消息的例子

抽象同事类

[java] view plaincopyprint?
  1. abstract class Colleague {  
  2.     // 引入中介者  
  3.     private Mediator mediator;  
  4.   
  5.     public Mediator getMediator() {  
  6.         return mediator;  
  7.     }  
  8.   
  9.     public Colleague(Mediator m) {  
  10.         mediator = m;  
  11.     }  
  12.   
  13.     // 消息  
  14.     private String message;  
  15.   
  16.     public String getMessage() {  
  17.         return message;  
  18.     }  
  19.   
  20.     public void setMessage(String message) {  
  21.         this.message = message;  
  22.     }  
  23.   
  24.     // 发送消息  
  25.     public abstract void sendMsg();  
  26.   
  27.     // 收到消息  
  28.     public abstract void getMsg(String msg);  
  29.   
  30.     // 发送消息  
  31.     public void sendMsg(String msg) {  
  32.         this.message = msg;  
  33.         mediator.action(this);  
  34.     }  
  35. }  

Colleague1

[java] view plaincopyprint?
  1. class Colleague1 extends Colleague {  
  2.   
  3.     public Colleague1(Mediator m) {  
  4.         super(m);  
  5.         // TODO Auto-generated constructor stub  
  6.     }  
  7.   
  8.     public void getMsg(String msg) {  
  9.         System.out.println("Colleague1 has got the message -'" + msg + "'");  
  10.     }  
  11.   
  12.     public void sendMsg() {  
  13.         System.out.println("Colleague1 has send the message '" + getMessage()  
  14.                 + "'");  
  15.     }  
  16. }  

Colleague2

[java] view plaincopyprint?
  1. class Colleague2 extends Colleague {  
  2.   
  3.     public Colleague2(Mediator m) {  
  4.         super(m);  
  5.         // TODO Auto-generated constructor stub  
  6.     }  
  7.   
  8.     public void getMsg(String msg) {  
  9.         System.out.println("Colleague2 has got the message -'" + msg + "'");  
  10.     }  
  11.   
  12.     public void sendMsg() {  
  13.         System.out.println("Colleague2 has send the message '" + getMessage()  
  14.                 + "'");  
  15.     }  
  16. }  

Colleague3

[java] view plaincopyprint?
  1. class Colleague3 extends Colleague {  
  2.   
  3.     public Colleague3(Mediator m) {  
  4.         super(m);  
  5.         // TODO Auto-generated constructor stub  
  6.     }  
  7.   
  8.     public void getMsg(String msg) {  
  9.         System.out.println("Colleague3 has got the message -'" + msg + "'");  
  10.     }  
  11.   
  12.     public void sendMsg() {  
  13.         System.out.println("Colleague3 has send the message '" + getMessage()  
  14.                 + "'");  
  15.     }  
  16. }  

抽象中介者

[java] view plaincopyprint?
  1. // 中介者  
  2. abstract class Mediator {  
  3. // Mediator针对Colleague的一个交互行为  
  4. public abstract void action(Colleague sender);  
  5.   
  6. // 加入Colleague对象  
  7. public abstract void addCollegue(Colleague colleague);  
  8. }  

中介者实现类

[java] view plaincopyprint?
  1. import java.util.ArrayList;  
  2. import java.util.List;  
  3.   
  4. class ConcreteMediator extends Mediator {  
  5.   
  6.     private List<Colleague> colleagues = new ArrayList<Colleague>(0);  
  7.   
  8.     public void addCollegue(Colleague colleague) {  
  9.         colleagues.add(colleague);  
  10.     }  
  11.   
  12.     public void action(Colleague actor) {  
  13.         String msg = actor.getMessage();  
  14.         // send msg  
  15.         for (Colleague colleague : colleagues) {  
  16.             if (colleague.equals(actor)) {  
  17.                 colleague.sendMsg();  
  18.                 break;  
  19.             }  
  20.         }  
  21.   
  22.         // got msg  
  23.         for (Colleague colleague : colleagues) {  
  24.             if (colleague.equals(actor))  
  25.                 continue;  
  26.             else  
  27.                 colleague.getMsg(msg);  
  28.         }  
  29.     }  
  30. }  

场景类

[java] view plaincopyprint?
  1. // 测试类  
  2. public class Client {  
  3.   
  4. public static void main(String[] args) {  
  5.    // 生成中介者 并注入到各个Colleague对象中  
  6.    Mediator mediator = new ConcreteMediator();  
  7.    Colleague colleague1 = new Colleague1(mediator);  
  8.    Colleague colleague2 = new Colleague2(mediator);  
  9.    Colleague colleague3 = new Colleague3(mediator);  
  10.   
  11.    // 注册对象到中介  
  12.    mediator.addCollegue(colleague1);  
  13.    mediator.addCollegue(colleague2);  
  14.    mediator.addCollegue(colleague3);  
  15.   
  16.    // Colleague1 触发行为  
  17.    colleague1.sendMsg("嗨,大家好!");  
  18.    System.out.println();  
  19.    // Colleague2 触发行为  
  20.    colleague2.sendMsg("很高兴见到你!");  
  21.    System.out.println();  
  22.    // Colleague3 触发行为  
  23.    colleague3.sendMsg("我们一起玩游戏吧!");  
  24.    System.out.println();  
  25. }  
  26. }  

运行结果

Colleague1 has send the message '嗨,大家好!'
Colleague2 has got the message -'嗨,大家好!'
Colleague3 has got the message -'嗨,大家好!'

Colleague2 has send the message '很高兴见到你!'
Colleague1 has got the message -'很高兴见到你!'
Colleague3 has got the message -'很高兴见到你!'

Colleague3 has send the message '我们一起玩游戏吧!'
Colleague1 has got the message -'我们一起玩游戏吧!'
Colleague2 has got the message -'我们一起玩游戏吧!'

 

六、中介者模式分析

(1)模式的功能

     中介者的功能非常简单,就是封装对象之间的交互。如果一个对象的操作会引起其它相关对象的变化,或者是某个操作需要引起其它对象的后续或连带操作,而这个对象又不希望自己来处理这些关系,那么就可以找中介者,把所有的麻烦扔给它,只在需要的时候通知中介者,其它的就让中介者去处理就可以了。

    反过来,其它的对象在操作的时候,可能会引起这个对象的变化,也可以这么做。最后对象之间就完全分离了,谁都不直接跟其它对象交互,那么相互的关系,全部被集中到中介者对象里面了,所有的对象就只是跟中介者对象进行通信,相互之间不再有联系。

把所有对象之间的交互都封装在中介者当中,无形中还得到另外一个好处,就是能够集中的控制这些对象的交互关系,这样有什么变化的时候,修改起来就很方便。

(2)需要Mediator接口吗

     要回答这个问题,先要搞清楚一件事情,接口用来干什么的?对,接口是用来实现“封装隔离”的,那么封装谁?隔离谁呢?Mediator接口嘛,肯定是用来封装中介者对象的,使得使用中介者对象的客户对象跟具体的中介者实现对象分离开。

       了解了上面这些内容,回过来想想,有没有使用Mediator接口的必要,那就取决于是否会提供多个不同的中介者实现。如果中介者实现只有一个的话,而且预计中也没有需要扩展的要求,那么就可以不定义Mediator接口,让各个同事对象直接使用中介者实现对象;如果中介者实现不只一个,或者预计中有扩展的要求,那么就需要定义Mediator接口,让各个同事对象来面向中介者接口编程,而无需关心具体的中介者实现。

(3)同事关系

       在标准的中介者模式中,把使用中介者对象来交互的那些对象称为同事类,这不是乱叫的,在中介者模式中,要求这些类都要继承相同的类,也就是说,这些对象从某个角度讲是同一个类型,算是兄弟对象。

       正是这些兄弟对象之间的交互关系很复杂,才产生了把这些交互关系分离出去,单独做成中介者对象,这样一来,这些兄弟对象就成了中介者对象眼里的同事。

(4)同事和中介者的关系

     在中介者模式中,当一个同事对象发生了改变,需要主动通知中介者,让中介者去处理与其它同事对象相关的交互。

     这就导致了同事对象和中介者对象之间必须有关系,首先是同事对象需要知道中介者对象是谁;反过来,中介者对象也需要知道相关的同事对象,这样它才能与同事对象进行交互。也就是说中介者对象和同事对象之间是相互依赖的。

(5)如何实现同事和中介者的通信

      一个同事对象发生了改变,会通知中介者对象,中介者对象会处理与其它同事的交互,这就产生了同事对象和中介者对象的相互通信。怎么实现这种通信关系呢?

      一种实现方式是在Mediator接口中定义一个特殊的通知接口,作为一个通用的方法,让各个同事类来调用这个方法,在中介者模式结构图里画的就是这种方式。定义了一个通用的changed方法,并且把同事对象当做参数传入,这样在中介者对象里面,就可以去获取这个同事对象的实例的数据了。

      另外一种实现方式是可以采用观察者模式,把Mediator实现成为观察者,而各个同事类实现成为Subject,这样同事类发生了改变,会通知Mediator。Mediator在接到通知过后,会与相应的同事对象进行交互。

七、广义中介者

仔细查看中介者的结构、定义和示例,会发现几个问题,使得中介者模式在实际使用的时候,变得繁琐或困难。

  • 其一:是否有必要为同事对象定义一个公共的父类?

大家都知道,Java是单继承的,为了使用中介者模式,就让这些同事对象继承一个父类,这是很不好的;再说了,这个父类目前也没有什么特别的公共功能,也就是说继承它也得不到多少好处。

在实际开发中,很多相互交互的对象本身是没有公共父类的,强行加上一个父类,会让这些对象实现起来特别别扭。

  • 其二:同事类有必要持有中介者对象吗?

同事类需要知道中介者对象,以便当它们发生改变的时候,能够通知中介者对象,但是,是否需要作为属性,并通过构造方法传入,这么强的依赖关系呢?

也可以有简单的方式去通知中介对象,比如把中介对象做成单例,直接在同事类的方法里面去调用中介者对象。

  • 其三:是否需要中介者接口?

在实际开发中,很常见的情况是不需要中介者接口的,而且中介者对象也不需要创建很多个实例,因为中介者是用来封装和处理同事对象的关系的,它一般是没有状态需要维护的,因此中介者通常可以实现成单例。

  • 其四:中介者对象是否需要持有所有的同事?

虽说中介者对象需要知道所有的同事类,这样中介者才能与它们交互。但是是否需要做为属性这么强烈的依赖关系,而且中介者对象在不同的关系维护上,可能会需要不同的同事对象的实例,因此可以在中介者处理的方法里面去创建、或者获取、或者从参数传入需要的同事对象。

  • 其五:中介者对象只是提供一个公共的方法,来接受同事对象的通知吗?

从示例就可以看出来,在公共方法里,还是要去区分到底是谁调过来,这还是简单的,还没有去区分到底是什么样的业务触发调用过来的,因为不同的业务,引起的与其它对象的交互是不一样的。

因此在实际开发中,通常会提供具体的业务通知方法,这样就不用再去判断到底是什么对象,具体是什么业务了。

 基于上面的考虑,在实际应用开发中,经常会简化中介者模式,来使开发变得简单,比如有如下的简化:

1.通常会去掉同事对象的父类,这样可以让任意的对象,只要需要相互交互,就可以成为同事;

2.还有通常不定义Mediator接口,把具体的中介者对象实现成为单例;

3.另外一点就是同事对象不再持有中介者,而是在需要的时候直接获取中介者对象并调用;中介者也不再持有同事对象,而是在具体处理方法里面去创建、或者获取、或者从参数传入需要的同事对象。

把这样经过简化、变形使用的情况称为广义中介者

①通常会去掉同事对象的父类,这样可以让任意的对象,只要需要相互交互,就可以成为同事。

②同事不定义Mediator接口,把具体的中介者实现成单例

③同事对象不再持有中介者对象,而是在具体处理方法里面去创建,或者获取,或者从参数传入需要的同事对象。

八、中介者模式的优缺点

8.1、优点

松散耦合
    中介者模式通过把多个同事对象之间的交互封装到中介者对象里面,从而使得同事对象之间松散耦合,基本上可以做到互不依赖。这样一来,同事对象就可以独立的变化和复用,而不再像以前那样“牵一发而动全身”了。

集中控制交互
    多个同事对象的交互,被封装在中介者对象里面集中管理,使得这些交互行为发生变化的时候,只需要修改中介者对象就可以了,当然如果是已经做好的系统,那就扩展中介者对象,而各个同事类不需要做修改。

多对多变成一对多
    没有使用中介者模式的时候,同事对象之间的关系通常是多对多的,引入中介者对象过后,中介者对象和同事对象的关系通常变成了双向的一对多,这会让对象的关系更容易理解和实现。

8.2、缺点

 过度集中化
    中介者模式的一个潜在缺点是,如果同事对象的交互非常多,而且比较复杂,当这些复杂性全部集中到中介者的时候,会导致中介者对象变得十分的复杂,而且难于管理和维护。

九、思考中介者模式

9.1、中介者模式的本质

中介者模式的本质:封装交互

    中介者模式的目的,就是用来封装多个对象的交互,这些交互的处理多在中介者对象里面实现,因此中介对象的复杂程度,就取决于它封装的交互有多复杂了。

    只要是实现封装对象之间的交互功能,就可以应用上中介者模式,而不必过于拘泥于中介者模式本身的结构。标准的中介者模式限制很多,导致能完全按照标准使用中介者模式的地方并不是很多,而且多集中在界面实现上。只要本质不变,稍稍变形一下,简化一下,或许能更好的使用中介者模式。

9.2、何时选用中介者模式

建议在如下情况中,选用中介者模式:

l  如果一组对象之间的通信方式比较复杂,导致相互依赖、结构混乱,可以采用中介者模式,把这些对象相互的交互管理起来,各个对象都只需要和中介者交互,从而使得各个对象松散耦合,结构也更清晰易懂。

l  如果一个对象引用很多的对象,并直接跟这些对象交互,导致难以复用该对象。可以采用中介者模式,把这个对象跟其它对象的交互封装到中介者对象里面,这个对象就只需要和中介者对象交互就可以了。

9.3、相关模式

9.3.1中介者模式和外观模式
    这两个模式有相似的地方,也存在很大的不同。
    外观模式多用来封装一个子系统内部的多个模块,目的是向子系统外部提供简单易用的接口,也就是说外观模式封装的是子系统外部和子系统内部模块间的交互;而中介者模式是提供多个平等的同事对象之间交互关系的封装,一般是用在内部实现上。
    另外,外观模式是实现单向的交互,是从子系统外部来调用子系统内部,不会反着来,而中介者模式实现的是内部多个模块间多向的交互。

9.3.2 中介者模式和观察者模式

中介者模式可以组合使用观察者模式,来实现当同事对象发生改变的时候,通知中介对象,让中介对象去进行与其它相关对象的交互。

参考:

部门人员例子  http://joe5456536.blog.163.com/blog/static/8537477320116364314234/

发送接收消息  http://hi.baidu.com/isswangqing/item/e80282145f12494fe75e06b3

进销存管理例子 设计模式之禅

0 0
原创粉丝点击