真刀实枪之中介者模式
-
进销存管理,你管理的头大吗?
- 你可能会说,这有啥难的,先来幅模块示意图
- 从这个示意图可以看出,三个模块是相互依赖的,其中:
- 销售情况:销售部门要反馈情况,畅销就多采购
- 库存情况:即使是畅销产品,库存多的话也不用去采购
- 从这个示意图可以看出,三个模块是相互依赖的,其中:
-
那好,先根据现况做出类图
-
代码
-
Purchase(采购管理)
package com.peng.zjz; /** * @author kungfu~peng * @data 2017年11月20日 * @description */ public class Purchase { // 采购IBM电脑 public void buyIBMComputer(int number) { // 访问库存 Stock stock = new Stock(); // 访问销售 Sale sale = new Sale(); // 电脑的销售情况 int saleSatus = sale.getSaleStatus(); if (saleSatus > 80) { // 销售良好 System.out.println("采购" + number + "台"); } else { // 销售情况不好 number /= 2;// 折半采购 System.out.println("采购" + number + "台"); } stock.increase(number); } // 不采购IBM电脑 public void refuseBuyIBM() { System.out.println("不采购IBM电脑"); } }
-
Stock(存货管理)
package com.peng.zjz; /** * @author kungfu~peng * @data 2017年11月20日 * @description */ public class Stock { // 开始有100的库存 private static int COMPUTER_NUMBER = 100; // 库存增加 public void increase(int number) { COMPUTER_NUMBER += number; System.out.println("库存容量:" + COMPUTER_NUMBER); } // 库存降低 public void decrease(int number) { COMPUTER_NUMBER -= number; System.out.println("库存容量:" + COMPUTER_NUMBER); } // 获取库存容量 public int getStockNumber() { return COMPUTER_NUMBER; } // 库存挺多,不需要采购,折价销售 public void clearStock() { Purchase pc = new Purchase(); Sale sale = new Sale(); System.out.println("清理库存容量为:" + COMPUTER_NUMBER); // 要求折价销售 sale.offSale(); // 要求采购人员不要采购 pc.refuseBuyIBM(); } }
-
Sale(销售管理)
package com.peng.zjz; import java.util.Random; /** * @author kungfu~peng * @data 2017年11月20日 * @description */ public class Sale { // 销售IBM电脑 public void sellIBMComputer(int number) { // 访问库存 Stock stock = new Stock(); // 访问采购 Purchase pc = new Purchase(); // 判断库存容量是否满足当前销售量 if (stock.getStockNumber() < number) { // 采购 pc.buyIBMComputer(number); } System.out.println("销售:" + number + "台!"); stock.decrease(number); } // 反馈销售情况--0代表没人买,100代表非常畅销,出一个买一个 public int getSaleStatus() { Random rand = new Random(System.currentTimeMillis()); int saleStatus = rand.nextInt(100); System.out.println("销售的情况为:" + saleStatus); return saleStatus; } public void offSale() { // 库房有多少卖多少 Stock stock = new Stock(); System.out.println("折价销售:" + stock.getStockNumber() + "台!"); } }
-
Client(场景类)
package com.peng.zjz; /** * @author kungfu~peng * @data 2017年11月20日 * @description */ public class Client { public static void main(String[] args) { // 采购人员采购电脑 Purchase pc = new Purchase(); pc.buyIBMComputer(100); // 销售人员销售电脑 Sale sale = new Sale(); sale.sellIBMComputer(1); // 库存清仓管理 Stock stock = new Stock(); stock.clearStock(); } }
-
执行结果(随机数的使用,你的结果也是随机的哦!)
销售的情况为:24 采购50台 库存容量:150 销售:1台! 库存容量:149 清理库存容量为:149 折价销售:149台! 不采购IBM电脑
-
-
-
上述代码中,每个类和另外两个类都产生了关联,耦合度有点高,牵一发而动全身,现在扩展一下,如图所示
- e!!理解也得理解半天,哈哈,写代码就快疯掉了!
- 诶,好像有个星型网比这个更简洁些,来个图看看!
- 有了参考,修改一下进销存管理系统
- 相应的,修改下类图
-
- 每个对象只与中介者产生关系,各个对象之间的耦合降低
- 中介者Mediator中,定义了多个private修饰的方法,其目的是处理各个对象之间的依赖关系。
- 三个同事只负责自己的事情,与自己无关的活动都让中介者来做,结果是相同的,结构更加清晰,而且类间的耦合度大大减少,代码的质量也大幅度提高
-
-
代码
-
AbstractMediator(抽象中介者)
package com.peng.zjz2; /** * @author kungfu~peng * @data 2017年11月20日 * @description */ public abstract class AbstractMediator { protected Purchase purchase; protected Sale sale; protected Stock stock; //构造函数 public AbstractMediator() { super(); purchase=new Purchase(this); sale=new Sale(this); stock=new Stock(this); } //中介者的最重要的方法--做事方法,处理多个对象间的关系 public abstract void execute(String str,Object...objects); }
-
Mediator(中介者)
package com.peng.zjz2; /** * @author kungfu~peng * @data 2017年11月20日 * @description */ public class Mediator extends AbstractMediator { @Override public void execute(String str, Object... objects) { if (str.equals("purchase.buy")) {// 采购电脑 this.buyComputer((Integer) objects[0]); } else if (str.equals("sale.sell")) {// 销售电脑 this.sellComputer((Integer) objects[0]); } else if (str.equals("sale.offsell")) {// 折价销售电脑 this.offSell(); } else if (str.equals("stock.clear")) {// 清仓处理 this.clearStock(); } } // 清仓处理 private void clearStock() { // 要求清仓销售 super.sale.offSale(); // 要求采购人员不要采购 super.purchase.refuseBuyIBM(); } // 折价销售 private void offSell() { System.out.println("折价销售" + super.stock.getStockNumber() + "台"); } // 销售电脑 private void sellComputer(Integer number) { if (super.stock.getStockNumber() < number) {// 库存不够销售进行购货 super.purchase.buyIBMComputer(number); } super.stock.decrease(number); } // 采购电脑 private void buyComputer(Integer number) { // 电脑的销售情况 int saleSatus = sale.getSaleStatus(); if (saleSatus > 80) { // 销售良好 System.out.println("采购" + number + "台"); } else { // 销售情况不好 number /= 2;// 折半采购 System.out.println("采购" + number + "台"); } } }
-
AbstractColleague(抽象同事)
package com.peng.zjz2; /** * @author kungfu~peng * @data 2017年11月20日 * @description */ public class AbstractColleague { protected AbstractMediator mediator; public AbstractColleague(AbstractMediator _mediator) { this.mediator = _mediator; } }
-
Purchase(采购管理)
package com.peng.zjz2; /** * @author kungfu~peng * @data 2017年11月20日 * @description */ public class Purchase extends AbstractColleague { public Purchase(AbstractMediator _mediator) { super(_mediator); } // 采购IBM电脑 public void buyIBMComputer(int number) { super.mediator.execute("purchase.buy", number); } // 不采购IBM电脑 public void refuseBuyIBM() { System.out.println("不采购IBM电脑"); } }
-
Sale(销售管理)
package com.peng.zjz2; import java.util.Random; /** * @author kungfu~peng * @data 2017年11月20日 * @description */ public class Sale extends AbstractColleague { public Sale(AbstractMediator _mediator) { super(_mediator); } // 销售IBM电脑 public void sellIBMComputer(int number) { super.mediator.execute("sale.sell", number); System.out.println("销售:" + number + "台!"); } // 反馈销售情况--0代表没人买,100代表非常畅销,出一个买一个 public int getSaleStatus() { Random rand = new Random(System.currentTimeMillis()); int saleStatus = rand.nextInt(100); System.out.println("销售的情况为:" + saleStatus); return saleStatus; } public void offSale() { super.mediator.execute("sale.offsell"); } }
-
Stock(库存管理)
package com.peng.zjz2; /** * @author kungfu~peng * @data 2017年11月20日 * @description */ public class Stock extends AbstractColleague { public Stock(AbstractMediator _mediator) { super(_mediator); } // 开始有100的库存 private static int COMPUTER_NUMBER = 100; // 库存增加 public void increase(int number) { COMPUTER_NUMBER += number; System.out.println("库存容量:" + COMPUTER_NUMBER); } // 库存降低 public void decrease(int number) { COMPUTER_NUMBER -= number; System.out.println("库存容量:" + COMPUTER_NUMBER); } // 获取库存容量 public int getStockNumber() { return COMPUTER_NUMBER; } // 库存挺多,不需要采购,折价销售 public void clearStock() { System.out.println("清理库存容量为:" + COMPUTER_NUMBER); // 要求折价销售 super.mediator.execute("stock.clear"); } }
-
- 你可能会说,这有啥难的,先来幅模块示意图
中介者模式的定义
- Define an Object that encapsulates how a set of objects interact.Mediator Promotes loose couping by kepping objects from referring to each other explicitly,and it lets you vary their interaction independentily.(用一个中介者封装一系列的对象交互,中介者使各个对象不需要显示地相互作用,从而使其耦合松散,而且可以独立地改变她们之间的交互)
- 类图
- 类图中的角色
- Mediator:抽象中介者--定义统一的接口,用于各同事角色之间的通讯
- ConcreteMediator:具体中介者角色--协调各同事之间的行为,依赖于各个同事
- Colleague:同事角色--每一个角色都知道中介者,当需要别的同事来做的事,他就会找中介者来间接做,不会直接找自己的同事【补充:自发行为--处理自己的行为;依赖方法--依赖中介才能完成的行为】
- 类图中的角色
-
通用代码
-
Mediator
package com.peng.zjz3; /** * @author kungfu~peng * @data 2017年11月20日 * @description */ public abstract class Mediator { // 定义同事类 protected ConcreteColleague1 c1; protected ConcreteColleague2 c2; // 通过getter/setter方法把同事类注入进来 public ConcreteColleague1 getC1() { return c1; } public void setC1(ConcreteColleague1 c1) { this.c1 = c1; } public ConcreteColleague2 getC2() { return c2; } public void setC2(ConcreteColleague2 c2) { this.c2 = c2; } // 中介者模式的业务逻辑 public abstract void doSomething1(); public abstract void doSomething2(); }
-
Colleague
package com.peng.zjz3; /** * @author kungfu~peng * @data 2017年11月20日 * @description */ public abstract class Colleague { protected Mediator mediator; public Colleague(Mediator _meditor) { this.mediator = _meditor; } }
-
ConcreteMediator
package com.peng.zjz3; /** * @author kungfu~peng * @data 2017年11月20日 * @description */ public class ConcreteMediator extends Mediator { @Override public void doSomething1() { //调用同事类的方法 super.c1.selfMehtod1(); super.c2.selfMehtod2(); } @Override public void doSomething2() { //调用同事类的方法 super.c1.selfMehtod1(); super.c2.selfMehtod2(); } }
-
同事1
package com.peng.zjz3; /** * @author kungfu~peng * @data 2017年11月20日 * @description */ public class ConcreteColleague1 extends Colleague { public ConcreteColleague1(Mediator _meditor) { super(_meditor); } // 自有方法 public void selfMehtod1() { // 处理自己的业务逻辑 } // 依赖方法--自己不能处理的业务逻辑,委托给中介者处理 public void depMethod1() { super.mediator.doSomething1(); } }
-
同事2
package com.peng.zjz3; /** * @author kungfu~peng * @data 2017年11月20日 * @description */ public class ConcreteColleague2 extends Colleague { public ConcreteColleague2(Mediator _meditor) { super(_meditor); } // 自有方法 public void selfMehtod2() { // 处理自己的业务逻辑 } // 依赖方法--自己不能处理的业务逻辑,委托给中介者处理 public void depMethod2() { super.mediator.doSomething1(); } }
- 在Mediator抽象类中我们只定义了同事类的注入,而不是同事抽象类的注入--那是因为同事类是虽然有抽象,但是没有每个同事必须要完成的业务方法; 为什么同事类要使用构造函数注入中介者,而中介者则通过setter/getter来注入同事类呢?这是因为同事类必须有中介者,而中介者却可以只有部分同事类
-
中介者的应用
- 中介者模式的优点
- 减少类间依赖
- 降低类间耦合
- 中介模式的缺点
- 中介者会膨胀很大
- 中介者逻辑复杂--同事类越多的时候
- 使用场景
- 量力而行--别使用后反而变得更加复杂
- 适用于多个对象的紧耦合的情况--蜘蛛网状的结构-->梳理成星型结构,使原本复杂的关系变得更加简单起来
实际应用
- 中介者模式也叫调停者模式--一个对象要和N个对象交流,就像对象间的战争,很混乱,这时加入一个中心,和所有类都进行交流,中心说怎么处理就怎么处理
- 机场调度中心--调度每一架飞机的起降
- MCV框架中的C(Controller)--前端控制器(Font Controller),它的作用就是把M(Model,业务逻辑)和V(View,视图)隔离开,协调M和V协同工作,减少他们之间的依赖
- 媒体网关--MSN服务器(中介者),中转站,接发信件【相反的是IPMsg--每个客户端集市客户端也是服务端】
- 中介服务--房屋中介、出国中介--主要是省心(其实是你嫌烦吧!!)
最佳实践
- 在中介者模式中,很少用到接口或者抽象类,这与依赖倒置的原则是冲突的,这是什么原因?
- 既然是同事类而不是兄弟类,那就说明这些类之间是协作关系,完成不同的任务,处理不同的业务,所以不能在抽象类或接口中定义同事类中具有的方法----可以看出,继承是有高侵入性的
- 使用时的情况
- N个对象之间产生了相互依赖的关系
- 多个对象有依赖关系,但是依赖的行为尚不确定或者有发生改变的可能-----降低变更引起的风险
- 产品开发(MVC框架),提升产品的性能和扩展性--稳定高效,扩展
声明
- 摘自秦小波《设计模式之禅》第2版;
- 仅供学习,严禁商业用途;
- 代码手写,没有经编译器编译,有个别错误,自行根据上下文改正。