18.23种设计模式之<中介者模式>

587 阅读7分钟

这是我参与8月更文挑战的第6天,活动详情查看:8月更文挑战

前言

前后端开发者每天都要用到的设计模式---中介者模式

前端开发伙伴, 有没有只写页面不需要调接口的? 不可能啊, 总不能都是假数据吧. 后端伙伴, 有没有只写接口不需要展示的? 也不可能啊, 那不白写了, 不然谁知道你写了啥. 那我们天天用什么方式来前后端交互呢? MVC, 很熟悉吧. MVC使用的就是中介者模式.

这个模型, 我们应该是再熟悉不过了. MVC三层结构, C作为中介者连接了M和V. 在没有三层结构的时候, 页面和业务逻辑耦合在一块, 页面直接调用业务逻辑, 导致业务逻辑越来越臃肿, 页面逻辑也越来越复杂, 不方便维护管理. 自从采用了三层结构, 将V直接分离出来, 前后端各司其职, 分工明确. MVC是中介者模式的典型应用.

再来看看我们每天使用的微信.

多个人聊天, 我们都是人到人聊天, 如何是这样, 我有10个好友, 就要建10个连接, 你又20个好友, 建立20个连接, 怎么可能, 这太耗费资源了. 其实在微信端有一个资源服务器, 所有人发的消息都是发到服务器上, 然后通过推送或者拉取的方式将消息显示在目标终端. 这个资源服务器就是中介者的一种.

说到中介, 大家脑袋里还会想到的是不是房屋中介, 无论是租房还是买房亦或者是卖房,都需要和房屋中介打交道。房屋中介连接买家和卖家,买家卖家不用自己练习,而是通过中介。中介者模式,起到的是中间人的作用.

一、什么是中介者模式?

​ 中介者模式是迪米特法则的最好应用。迪米特法则说,一个对象只和朋友沟通,而朋友不是越多越好,朋友越多,相互之间的耦合性就越大。

​ (到底什么是一个对象的朋友呢? 可以参考文章--迪米特法则 -- juejin.cn/post/696728…)

​ 那么到底是什么是中介者呢?我们来举个例子。以超市购物为例,超市里有各种各样的商品,还有推销商品的销售人员,商品卖出以后从库存补货,如果库存也不足,就要采买。我们来看看这里面涉及到哪些部门,销售部门,库存部门,采购部门,他们之间的关系如下:

我们看到上面三个部门相互之间存在着信息交流。每个部门都可能和另外两个部门产生关系,而现在,知识有3个部门,实际情况要比这负载的多,中间会增加两个,三个甚至更多的部门,每个部门都和所有其他的部门进行交互,就会非常凌乱,且容易出错,这时要是有一个中间人,专门来处理这些问题,那么,情况就会清晰很多。

这就是中介者模式的核心思想。

中介者模式(Mediator Pattern):提供了一个中介类来封装一系列的对象及其交互,中介者使各对象不需要显示地相互作用。这个中介类,通常处理不同类之间的通信,并支持松耦合,使代码易于维护。中介者模式属于行为型模式。

二、中介者模式的结构及其实现

来看终结者模式的UML图:

从图中我们总结以下结构:

  1. 抽象同事类: "同事"这两个字可以理解为相互平等的等级关系. 根据中介者模式的定义, 每一个"同事"都是和中介者打交道, 所以, 需要定义打交道的中介者是谁.
  2. 具体同事类: 比如在这里我们的销售部门, 库存部门, 采购部门就是相互平级的部门, 他们之间就可以理解为同事关系.
  3. 抽象中介者类: 抽象中介者 定义了通用的任务行为
  4. 具体中介者类: 具体需要执行的操作. 通常具体中介者要和所有的"同事"打交道, 所以里面会定义所有的同事类.

具体源码逻辑实现如下:

第一步: 抽象"同事"类.

package com.lxl.www.designPatterns.mediatorPattern18.supermarket;

/**
 * 部门
 */
public abstract class IDepartment {

    public final static String COMMUNICATION_TYPE_ADD_PRODUCT = "add product";
    public final static String COMMUNICATION_TYPE_ADD_PRODUCT_FINISH = "addProductFinish";
    public final static String COMMUNICATION_TYPE_PURCHASE = "purchase";
    public final static String COMMUNICATION_TYPE_PURCHASE_FINISH = "purchased";
    public final static String COMMUNICATION_TYPE_PURCHASEING = "purchaseing";
    //private final static String COMMUNICATION_TYPE_ADD_PRODUCT = "add product";

    // 商品数量
    int productNum = 0;

    /**
     * 需要和中介进行沟通交流
     */
    IMediator mediator;

    abstract void setProductNum(Integer productNum);

    public IDepartment(IMediator mediator) {
        this.mediator = mediator;
    }

    /**
     * 部门内自己的工作
     */
    public abstract void work(Integer num);

    /**
     * 和其他部门的沟通交流
     */
    public abstract void communicat(String communicationType);


}

每一个部门都有自己要做的工作, 以及和其他部门进行交流, 自己的工作自己做即可, 和其他部门进行交流的部分, 交给中介者, 让中介者来转发处理.

第二步: 具体的"同事"类

这里面具体的同事类就是具体的部门, 销售部门、库存部门,采购部门

销售部门

package com.lxl.www.designPatterns.mediatorPattern18.supermarket;


/**
 * 销售部门
 */
public class SaleDepartment extends IDepartment {

    public SaleDepartment(IMediator mediator) {
        super(mediator);
    }

    public void setProductNum(Integer productNum) {
        this.productNum += productNum;
    }


    /** 销售商品 */
    @Override
    public void work(Integer num) {
        if (productNum > num) {
            System.out.println("当前货架商品有 "+productNum+" 件, 销售了" + num + "件");
            this.productNum -= num;
            if (this.productNum > 20) {
                System.out.println("剩余商品"+productNum+"件, 货品充足");
            } else {
                // 补品不足, 通知补货
                System.out.println("剩余商品"+productNum+"件, 货品不足");
                communicat(COMMUNICATION_TYPE_ADD_PRODUCT);
            }
        } else {
            // 商品不足, 通知补货
            communicat(COMMUNICATION_TYPE_ADD_PRODUCT);
        }
    }

    @Override
    public void communicat(String communicationType) {
        if (communicationType.equals(COMMUNICATION_TYPE_ADD_PRODUCT)) {
            System.out.println("货品不足, 需要补货");
            mediator.operate(communicationType, 50);
        } else if (communicationType.equals(COMMUNICATION_TYPE_ADD_PRODUCT_FINISH)) {
            setProductNum(10);
            work(0);
        } else if (communicationType.equals(COMMUNICATION_TYPE_PURCHASEING)) {
            System.out.println("库存不足, 采购中....");
        }
    }
}

库存部门

package com.lxl.www.designPatterns.mediatorPattern18.supermarket;

/**
 * 库存部门
 */
public class StockDepartment extends IDepartment{
    public StockDepartment(IMediator mediator) {
        super(mediator);
    }

    public void setProductNum(Integer productNum) {
        this.productNum = productNum;
    }

    @Override
    public void work(Integer num) {
        System.out.println("当前库存:"+this.productNum);
        // 补货成功标志
        boolean flag = false;
        if (this.productNum >= num) {
            System.out.println("取走存货"+num+"件");
            this.productNum -= num;
            flag = true;
        } else {
            System.out.println("存货不足, 无法补货. 需要采购");
            flag = false;
        }

        // 这里应该是异步通知仓库不足,需要采买
        if (productNum > 100) {
            System.out.println("仓库存库充足!");
        } else {
            communicat(COMMUNICATION_TYPE_PURCHASE);
        }

        if (flag) {
            communicat(COMMUNICATION_TYPE_ADD_PRODUCT_FINISH);
        } else {
            communicat(COMMUNICATION_TYPE_PURCHASEING);
        }
    }

    @Override
    public void communicat(String communicationType) {
        if (communicationType.equals(COMMUNICATION_TYPE_PURCHASE)) {
            //System.out.println("仓库库存不足, 需要采购");
            mediator.operate(COMMUNICATION_TYPE_PURCHASE, 0);
        } else if (communicationType.equals(COMMUNICATION_TYPE_ADD_PRODUCT_FINISH))  {
           // System.out.println("仓库库存补货完成");
            mediator.operate(COMMUNICATION_TYPE_ADD_PRODUCT_FINISH, 0);
        } else if(communicationType.equals(COMMUNICATION_TYPE_PURCHASEING)) {
            // 库存不足,采买中....
            mediator.operate(COMMUNICATION_TYPE_ADD_PRODUCT_FINISH, 0);
        }
    }
}

采购部门

package com.lxl.www.designPatterns.mediatorPattern18.supermarket;

/**
 * 采购部门
 */
public class PurchaseDepartment extends IDepartment {
    @Override
    void setProductNum(Integer productNum) {

    }

    public PurchaseDepartment(IMediator mediator) {
        super(mediator);
    }

    @Override
    public void work(Integer num) {
        this.productNum += num;
        System.out.println("采购商品完成");
    }
/**
 * 
 */
    @Override
    public void communicat(String communicationType) {
        mediator.operate(communicationType, this.productNum);
    }
}

第三步: 抽象的中介者

package com.lxl.www.designPatterns.mediatorPattern18.supermarket;

/**
 * 中介者接口
 */
public interface IMediator {


    void operate(String type, Integer num);

}

第四步: 具体的中介者

package com.lxl.www.designPatterns.mediatorPattern18.supermarket;

/**
 * 具体的中介者
 */
public class ConcreteMediator implements IMediator {
    IDepartment sale;
    IDepartment stock;
    IDepartment purchase;

    @Override
    public void operate(String type, Integer num) {
        if (IDepartment.COMMUNICATION_TYPE_ADD_PRODUCT.equals(type)) {
            //System.out.println("通知库存补货");
            stock.work(num);
        } else if (IDepartment.COMMUNICATION_TYPE_PURCHASE.equals(type)) {
            //System.out.println("通知采购部门补货");
            purchase.work(num);
        } else if (IDepartment.COMMUNICATION_TYPE_ADD_PRODUCT_FINISH.equals(type)) {
            //System.out.println("通知销售部门和库存, 补货完成");
            sale.communicat(type);
        } else if (IDepartment.COMMUNICATION_TYPE_PURCHASEING.equals(type)) {
            //System.out.println("通知销售部门, 库存不足, 采购中....");
            sale.communicat(type);
        } else if (IDepartment.COMMUNICATION_TYPE_PURCHASE_FINISH.equals(type)) {
            System.out.println("采购完成, 可以取货");
        }
    }

    public IDepartment getSale() {
        return sale;
    }

    public void setSale(IDepartment sale) {
        this.sale = sale;
    }

    public IDepartment getStock() {
        return stock;
    }

    public void setStock(IDepartment stock) {
        this.stock = stock;
    }

    public IDepartment getPurchase() {
        return purchase;
    }

    public void setPurchase(IDepartment purchase) {
        this.purchase = purchase;
    }
}

第五步: 客户端调用

package com.lxl.www.designPatterns.mediatorPattern18.supermarket;

/**
 * 客户端
 */
public class Client {
    public static void main(String[] args) {
        // 中介者
        ConcreteMediator mediator = new ConcreteMediator();
        // 销售部门
        IDepartment sale = new SaleDepartment(mediator);
        // 库存部门
        IDepartment stock = new StockDepartment(mediator);


        // 采购部门
        IDepartment purchase = new PurchaseDepartment(mediator);

        mediator.setSale(sale);
        mediator.setPurchase(purchase);
        mediator.setStock(stock);

        // 销售商品剩余数量
        sale.setProductNum(30);
        System.out.println("商品库存:" + sale.productNum);
        System.out.println("======售出5件======");
        sale.work(5);

        System.out.println("======售出10件======");
        sale.work(10);
        //stock.communicat();

    }
}

第六步: 运行结果

商品库存:30
======售出5件======
当前货架商品有 30 件, 销售了5件
剩余商品25件, 货品充足
======售出10件======
当前货架商品有 25 件, 销售了10件
剩余商品15件, 货品不足
货品不足, 需要补货
当前库存:0
存货不足, 无法补货. 需要采购
采购商品完成
当前货架商品有 25 件, 销售了0件
剩余商品25件, 货品充足

这样就实现了, 各个部门都是和中介交流, 而不需要和每一个具体的部门交流了