中介者模式/调停者模式

通过进销存分析

比如 XX 超市,采购部门要采购 IBM 型号的电脑了,它是根据什么来决定采购的呢?

- 销售情况。销售部门要反馈销售情况,畅销就多采购,滞销就不采购;

- 库存情况。即使是畅销产品,库存都有 1000 台了,每天才卖出去 10 台,还要采购吗?

- 采购。在特殊情况下,比如一个企业客户一下子要卖 100 台电脑,你库存里自由 80 台,怎么办?催采购部门赶快采购呀

从以上分析来看,这三个模块都是有自己的行为,并且与其他模块之间的行为产生关联关系

进销存类图:

Purchase 负责采购管理,buyIBMComputer 是指定了采购 IBM 电脑,refuseBuyIBM 是不再采购 IBM 了

public class Purchase {

    //采购IBM型号的电脑

    public void buyIBMcomputer(int number){

        //访问库存

        Stock stock = new Stock();

        //访问销售

        Sale sale = new Sale();

        //电脑的销售情况

        int saleStatus = sale.getSaleStatus();

        if(saleStatus>80){ //销售情况良好

            System.out.println("采购IBM电脑:"+number + "台");

            stock.increase(number);

        }else{ //销售情况不好

            int buyNumber = number/2; //折半采购

            System.out.println("采购IBM电脑:"+buyNumber+ "台");

        }

    }

    //不再采购IBM电脑

    public void refuseBuyIBM(){

        System.out.println("不再采购IBM电脑");

    }

}

Purchase 定义了采购电脑的一个标准,如果销售情况比较好,大于 80 分,你让我采购多少我就采购多少;销售情况不好,你让我采购 100 台,我就采购 50 台,对折采购。电脑采购完毕了,肯定要放到库房中,因此要调用库存的方法,增加库存电脑数量。

库房 Stock 类:

public class Stock {

    //刚开始有100台电脑

    private static int COMPUTER_NUMBER =100;

    //库存增加

    public void increase(int number){

        COMPUTER_NUMBER = COMPUTER_NUMBER + number;

        System.out.println("库存数量为:"+COMPUTER_NUMBER);

    }

    //库存降低

    public void decrease(int number){

        COMPUTER_NUMBER = COMPUTER_NUMBER - number;

        System.out.println("库存数量为:"+COMPUTER_NUMBER);

    }

    //获得库存数量

    public int getStockNumber(){

        return COMPUTER_NUMBER;

    }

    //存货压力大了,就要通知采购人员不要采购,销售人员要尽快销售

    public void clearStock(){

        Purchase purchase = new Purchase();

        Sale sale = new Sale();

        System.out.println("清理存货数量为:"+COMPUTER_NUMBER);

        //要求折价销售

        sale.offSale();

        //要求采购人员不要采购

        purchase.refuseBuyIBM();

    }

}

库房中的货物数量肯定有增加和减少了,同时库房还有一个容量显示,达到一定的容量后就要求对一些商品进行折价处理,腾出更多的空间容纳新产品,于是就有了 clearStock 方法,既然是清仓处理肯定就要折价销售了,于是在 Sale 这个类中就有了 offSale 方法。

Sale 源代码:

public class Sale {

    //销售IBM型号的电脑

    public void sellIBMComputer(int number){

        //访问库存

        Stock stock = new Stock();

        //访问采购

        Purchase purchase = new Purchase();

        if(stock.getStockNumber()

            purchase.buyIBMcomputer(number);

        }

        System.out.println("销售IBM电脑"+number+"台");

        stock.decrease(number);

    }

    //反馈销售情况,0——100之间变化,0代表根本就没人卖,100代表非常畅销,出一个卖一个

    public int getSaleStatus(){

        Random rand = new Random(System.currentTimeMillis());

        int saleStatus = rand.nextInt(100);

        System.out.println("IBM电脑的销售情况为:"+saleStatus);

        return saleStatus;

    }

    //折价处理

    public void offSale(){

        //库房有多少卖多少

        Stock stock = new Stock();

        System.out.println("折价销售IBM电脑"+stock.getStockNumber()+"台");

    }

}

Sale 类中的 getSaleStatus 是获得销售情况,这个当然要出现在 Sale 类中了,记住恰当的类放到恰当的类中,销售情况当然只有销售人员才能反馈出来了,通过百分制的机制衡量销售情况。

public class Client {

    public static void main(String[] args) {

        //采购人员采购电脑

        System.out.println("------采购人员采购电脑--------");

        Purchase purchase = new Purchase();

        purchase.buyIBMcomputer(100);

        //销售人员销售电脑

        System.out.println("\n------销售人员销售电脑--------");

        Sale sale = new Sale();

        sale.sellIBMComputer(1);

        //库房管理人员管理库存

        System.out.println("\n------库房管理人员清库处理--------");

        Stock stock = new Stock();

        stock.clearStock();

    }

}

场景类中模拟了三种人员类型的活动:采购人员采购电脑,销售人员销售电脑,库管员管理库存,运行结果如下:

------采购人员采购电脑--------

IBM 电脑的销售情况为:95

采购 IBM 电脑:100 台

库存数量为:200

------销售人员销售电脑--------

销售 IBM 电脑 1 台

库存数量为:199

------库房管理人员清库处理--------

清理存货数量为:199

折价销售 IBM 电脑 199 台

不再采购 IBM 电脑

迪米特法则教育我们“每个类只和朋友类交流”,这个朋友类可不是越多越好,越多耦合性越大,改一个对象而要修改一片对象,这可不是面向对象设计所期望的,而且这还是就三个模块的情况,比较简单的一个小项目,如果有十个八个这样的模块是不是就要歇菜了,我们把进销存扩充一下,如下图的情况:

星型网络拓扑中每个计算机通过交换机和其他计算机进行数据交换,各个计算机之间并没有直接出现交互的情况,结构简单,而且稳定,只要中间那个交换机不瘫痪,整个网络就不会发生大的故障,公司和网吧一般都采用星型网络,那也说明星型拓扑是深得民心,那我们来想想是不是可以把这种星型结构引入到我们的设计中呢?


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


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

public abstract class AbstractMediator {

    protected Purchase purchase;

    protected Sale sale;

    protected Stock stock;

    //构造函数

    public AbstractMediator(){

        purchase = new Purchase(this);

        sale = new Sale(this);

        stock = new Stock(this);

    }

    //中介者最重要的方法,叫做事件方法,处理多个对象之间的关系

    public abstract void execute(String str,Object...objects);

}

我们再来看具体的中介者,中介者可以根据业务的要求产生多个中介者(一般情况只有一个中介者)

public class Mediator extends AbstractMediator {

    //中介者最重要的方法

    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 buyComputer(int number){

        int saleStatus = super.sale.getSaleStatus();

        if(saleStatus>80){ //销售情况良好

            System.out.println("采购IBM电脑:"+number + "台");

            super.stock.increase(number);

        }else{ //销售情况不好

            int buyNumber = number/2; //折半采购

            System.out.println("采购IBM电脑:"+buyNumber+ "台");

        }

    }

    //销售电脑

    private void sellComputer(int number){

        if(super.stock.getStockNumber()

            super.purchase.buyIBMcomputer(number);

        }

        super.stock.decrease(number);

    }

    //折价销售电脑

    private void offSell(){

        System.out.println("折价销售IBM电脑"+stock.getStockNumber()+"台");

    }

    //清仓处理

    private void clearStock(){

        //要求清仓销售

        super.sale.offSale();

        //要求采购人员不要采购

        super.purchase.refuseBuyIBM();

    }

}

中介者 Mediator 有定义了多个 Private 方法,其目标是处理各个对象之间的依赖关系,即是说把原有一个对象要依赖多个对象的情况移到中介者的 Private 方法中实现,在实际项目中,一般的做法是中介者按照职责进行划分,每个中介者处理一个或多个类似的关联请求。

AbstractColleague 源码:

public abstract class AbstractColleague {

    protected AbstractMediator mediator;

    public AbstractColleague(AbstractMediator _mediator){

        this.mediator = _mediator;

    }

}

采购类 Purchase 的源码如下:

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电脑");

    }

}

Purchase 类是不是简化了很多,看着也清晰了很多,处理自己的职责,与外界有关系的事件处理则交给了中介者来完成.

Stock 类:

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 = COMPUTER_NUMBER + number;

        System.out.println("库存数量为:"+COMPUTER_NUMBER);

    }

    //库存降低

    public void decrease(int number){

        COMPUTER_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");

    }

}

Sale 类的源码:

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("销售IBM电脑"+number+"台");

    }

    //反馈销售情况,0——100之间变化,0代表根本就没人卖,100代表非常畅销,出1一个卖一个

    public int getSaleStatus(){

        Random rand = new Random(System.currentTimeMillis());

        int saleStatus = rand.nextInt(100);

        System.out.println("IBM电脑的销售情况为:"+saleStatus);

        return saleStatus;

    }

    //折价处理

    public void offSale(){

        super.mediator.execute("sale.offsell");

    }

}

再来看场景类的变化

public class Client {

    public static void main(String[] args) {

        AbstractMediator mediator = new Mediator();

        //采购人员采购电脑

        System.out.println("------采购人员采购电脑--------");

        Purchase purchase = new Purchase(mediator);

        purchase.buyIBMcomputer(100);

        //销售人员销售电脑

        System.out.println("\n------销售人员销售电脑--------");

        Sale sale = new Sale(mediator);

        sale.sellIBMComputer(1);

        //库房管理人员管理库存

        System.out.println("\n------库房管理人员清库处理--------");

        Stock stock = new Stock(mediator);

        stock.clearStock();

    }

}

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

通用类图为:


从类图中看,中介者模式有以下几部分组成:

抽象中介者(Mediator)角色:抽象中介者角色定义统一的接口用于各同事角色之间的通信。

具体中介者(Concrete Mediator)角色:具体中介者角色通过协调各同事角色实现协作行为,因此它必须依赖于各个同事角色。

同事(Colleague)角色:每一个同事角色都知道中介者角色,而且与其他的同事角色通信的时候,一定要通过中介者角色协作。每个同事类的行为分为两种:一种是同事本身的行为,比如改变对象本身的状态,处理自己的行为等等,这种方法叫做自发行为(Self-Method),与其他的同事类或中介者没有任何的依赖;第二种是是必须依赖中介者才能完成的行为,叫做依赖方法(Dep-Method)。

你可能感兴趣的:(中介者模式/调停者模式)