设计模式之禅【中介者模式】

真刀实枪之中介者模式

  • 进销存管理,你管理的头大吗?

    • 你可能会说,这有啥难的,先来幅模块示意图
      • 从这个示意图可以看出,三个模块是相互依赖的,其中:
        1. 销售情况:销售部门要反馈情况,畅销就多采购
        2. 库存情况:即使是畅销产品,库存多的话也不用去采购
    • 那好,先根据现况做出类图

      • 代码

        • 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!!理解也得理解半天,哈哈,写代码就快疯掉了!
      • 诶,好像有个星型网比这个更简洁些,来个图看看!
      • 有了参考,修改一下进销存管理系统
      • 相应的,修改下类图
          1. 每个对象只与中介者产生关系,各个对象之间的耦合降低
          2. 中介者Mediator中,定义了多个private修饰的方法,其目的是处理各个对象之间的依赖关系。
          3. 三个同事只负责自己的事情,与自己无关的活动都让中介者来做,结果是相同的,结构更加清晰,而且类间的耦合度大大减少,代码的质量也大幅度提高
      • 代码

        • 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.(用一个中介者封装一系列的对象交互,中介者使各个对象不需要显示地相互作用,从而使其耦合松散,而且可以独立地改变她们之间的交互)
  • 类图
    • 类图中的角色
      1. Mediator:抽象中介者--定义统一的接口,用于各同事角色之间的通讯
      2. ConcreteMediator:具体中介者角色--协调各同事之间的行为,依赖于各个同事
      3. 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来注入同事类呢?这是因为同事类必须有中介者,而中介者却可以只有部分同事类

中介者的应用

  • 中介者模式的优点
    1. 减少类间依赖
    2. 降低类间耦合
  • 中介模式的缺点
    1. 中介者会膨胀很大
    2. 中介者逻辑复杂--同事类越多的时候
  • 使用场景
    1. 量力而行--别使用后反而变得更加复杂
    2. 适用于多个对象的紧耦合的情况--蜘蛛网状的结构-->梳理成星型结构,使原本复杂的关系变得更加简单起来

实际应用

  • 中介者模式也叫调停者模式--一个对象要和N个对象交流,就像对象间的战争,很混乱,这时加入一个中心,和所有类都进行交流,中心说怎么处理就怎么处理
  • 机场调度中心--调度每一架飞机的起降
  • MCV框架中的C(Controller)--前端控制器(Font Controller),它的作用就是把M(Model,业务逻辑)和V(View,视图)隔离开,协调M和V协同工作,减少他们之间的依赖
  • 媒体网关--MSN服务器(中介者),中转站,接发信件【相反的是IPMsg--每个客户端集市客户端也是服务端】
  • 中介服务--房屋中介、出国中介--主要是省心(其实是你嫌烦吧!!)

最佳实践

  • 在中介者模式中,很少用到接口或者抽象类,这与依赖倒置的原则是冲突的,这是什么原因?
    • 既然是同事类而不是兄弟类,那就说明这些类之间是协作关系,完成不同的任务,处理不同的业务,所以不能在抽象类或接口中定义同事类中具有的方法----可以看出,继承是有高侵入性的
  • 使用时的情况
    1. N个对象之间产生了相互依赖的关系
    2. 多个对象有依赖关系,但是依赖的行为尚不确定或者有发生改变的可能-----降低变更引起的风险
    3. 产品开发(MVC框架),提升产品的性能和扩展性--稳定高效,扩展

声明

  • 摘自秦小波《设计模式之禅》第2版;
  • 仅供学习,严禁商业用途;
  • 代码手写,没有经编译器编译,有个别错误,自行根据上下文改正。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

乘风御浪云帆之上

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值