设计模式(十四)中介者模式

相关文章
设计模式(一)设计六大原则
设计模式(二)单例模式的七种写法
设计模式(三)建造者模式
设计模式(四)简单工厂模式
设计模式(五)观察者模式
设计模式(六)代理模式
设计模式(七)装饰模式
设计模式(八)外观模式
设计模式(九)模版方法模式
设计模式(十)工厂方法模式
设计模式(十一)策略模式
设计模式(十二)享元模式
设计模式(十三)抽象工厂模式javascript

前言

写了不少篇设计模式的文章,才发现没有讲关于设计模式的分类,那么这一篇就补上这一内容,顺便带来中介者模式的讲解。并与此前讲过的代理模式和外观模式作对比。java

1.设计模式的分类

GoF提出的设计模式总共有23种,根据目的准则分类分为三大类:git

  • 建立型模式,共五种:单例模式、工厂方法模式、抽象工厂模式、建造者模式、原型模式。
  • 结构型模式,共七种:适配器模式、装饰模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
  • 行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代器模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

另外随着设计模式的发展也涌现出不少新的设计模式:它们分别是规格模式、对象池模式、雇工模式、黑板模式和空对象模式等。github

2.中介者模式

从前面讲到的设计模式的分类中,咱们应该得知中介者模式是行为型模式的一种,旨在处理类或对象如何交互及如何分配职责。
中介者模式又叫作调停者模式,名字跟出国留学中介和房产中介是相似的。拿房产中介来讲,如今房子买家和房子卖家很是多,若是任由房子买家和房子卖家自由交易,则会致使不一样的买家和卖家之间有不少交互,一个买家会和多个卖家进行交涉,一样的一个卖家也会和多个买家进行交涉。若是在买房的过程当中出现纠纷问题,则很难进行解决。就以下图所示同样。设计模式

能够看出房子买家和卖家进行了不少错综复杂的交互,而且买家A和卖家B,买家D和卖家D还产生了纠纷,一看到这个图咱们就以为的晕,固然比咱们晕的还有房子买家和卖家。咱们在 设计模式(一)设计六大原则这篇文章讲过迪米特原则,这个原则所说的就是要尽可能减小对象之间的交互,若是两个对象之间没必要彼此直接通讯,那么这两个对象就不该当发生任何直接的相互做用,若是其中的一个对象须要调用另外一个对象的某一个方法的话,能够经过第三者转发这个调用。迪米特原则一样适用于本场景,咱们能够引入第三者也就是房产中介。它的出现不须要买家和卖家进行直接交涉,而是经过房产中介而进行交涉。而且也不容易出现买卖家之间纠纷,由于有中介者房产中介进行第三方监督。以下图所示。
微信

图中的关系清晰了不少。回到咱们软件开发中,咱们为了减小对象之间的交互和耦合,符合迪米特原则,那么就可使用中介者模式,先来学习下中介者模式的定义。
中介者模式定义
定义:用一个中介者对象来封装一系列的对象交互。中介者使得各对象不须要显式地相互引用,从而使其松散耦合,并且能够独立地改变它们之间的交互。ide

中介者模式结构图以下图所示。 学习


在中介者模式中有以下角色:

  • Mediator:抽象中介者角色,定义了同事对象到中介者对象的接口。
  • ConcreteMediator:具体中介者角色,它从具体的同事对象接收消息,向具体同事发出命令。
  • Colleague:抽象同事角色,定义了中介者对象接口,它只知道中介者而不知道其余同事对象。
  • ConcreteColleague:具体同事角色,每一个具体同事类都知道本身在小范围内的行为,而不知道它在大范围内的目的。

中介者模式简单实现
中介者模式能够拿武侠来举例,江湖中门派众多,门派以前由于想法不一样会有不少的利益冲突,这样就会带来无休止的纷争。为了江湖的安宁,你们推举出了一个你们都承认的武林盟主来对江湖纷争进行调停。
前段时间武当派和峨眉派的的弟子被大力金刚指所杀,大力金刚指是少林派的绝学,由于事情重大,并且少林派实力强大,武当派和峨眉派不可以直接去少林派去问罪,只能上报武林盟主由武林盟主出面进行调停,以下图所示。ui

抽象中介者角色
首先咱们建立抽象中介者类,在这个例子中,它是一个武林联盟类,以下所示。this

public abstract class WulinAlliance {
    public abstract void notice(String message, United united);
}复制代码

notice方法用于向门派发送通知,其中United为抽象同事类也就是门派类,接下来咱们来建立它。

抽象同事角色

public abstract class United {
    protected WulinAlliance wulinAlliance;
    public United(WulinAlliance wulinAlliance){
        this.wulinAlliance=wulinAlliance;
    }
}复制代码

门派类(抽象同事类)会在构造方法中获得武林联盟类(抽象中介者类)。

具体同事角色
具体同事类包括武当派、峨眉派和少林派,以下所示。

/** * 具体同事类(武当) */

public class Wudang extends United {
    public Wudang(WulinAlliance wulinAlliance) {
        super(wulinAlliance);
    }
    public void sendAlliance(String message) {
        wulinAlliance.notice(message, this);
    }
    public void getNotice(String message) {
        System.out.println("武当收到消息:" + message);
    }
}

/** * 具体同事类(峨眉派) */
public class Emei extends United {
    public Emei(WulinAlliance wulinAlliance) {
        super(wulinAlliance);
    }
    public void sendAlliance(String message) {
        wulinAlliance.notice(message, Emei.this);
    }
    public void getNotice(String message) {
        System.out.println("峨眉收到消息:" + message);
    }
}

/** * 具体同事类(少林派) */
public class Shaolin extends United {
    public Shaolin(WulinAlliance wulinAlliance) {
        super(wulinAlliance);
    }
    public void sendAlliance(String message){
        wulinAlliance.notice(message,Shaolin.this);
    }
    public void getNotice(String message){
        System.out.println("少林收到消息:"+message);
    }
}复制代码

武当、峨眉和少林类都有两个方法,其中getNotice方法是自有方法,对于其余的门派(同事类)和武林联盟(中介者)没有依赖,只是用来接收武林盟主的通知。sendAlliance方法则是依赖方法,它必须经过武林盟主才能完成行为。

具体中介者角色
具体中介者类则是武林盟主类,以下所示

public class Champions extends WulinAlliance {
    private Wudang wudang;
    private Shaolin shaolin;
    private Emei emei;
    public void setWudang(Wudang wudang) {
        this.wudang = wudang;
    }
    public void setEmei(Emei emei) {
        this.emei = emei;
    }
    public void setShaolin(Shaolin shaolin) {
        this.shaolin = shaolin;
    }
    @Override
    public void notice(String message, United united) {
        if (united == wudang) {
            shaolin.getNotice(message);
        } else if (united == emei) {
            shaolin.getNotice(message);
        } else if (united == shaolin) {
            wudang.getNotice(message);
            emei.getNotice(message);
        }
    }
}复制代码

武林盟主须要了解全部的门派,因此须要用setter来持有武当、峨眉和少林的引用。notice方法会根据不一样门派发来的消息,转而通知给其余的门派。好比武当发来的消息,武林盟主就会将消息通知给少林。

客户端调用

public class Client {
    public static void main(String[]args) {
        Champions champions=new Champions();
        Wudang wudang=new Wudang(champions);
        Shaolin shaolin=new Shaolin(champions);
        Emei emei=new Emei(champions);
        champions.setWudang(wudang);
        champions.setShaolin(shaolin);
        champions.setEmei(emei);
        wudang.sendAlliance("武当弟子被少林大力金刚指所杀");
        emei.sendAlliance("峨眉弟子被少林大力金刚指所杀");
        shaolin.sendAlliance("少林弟子毫不会作出这种事情");
    }
}复制代码

首先建立武林盟主类Champions 并传入到各个门派类,接着调用武林盟主类的setter方法传入各个门派类,最后调用各个门派的sendAlliance方法经过武林盟主类向其余门派发送消息。

输出结果为:
少林收到消息:武当弟子被少林大力金刚指所杀
少林收到消息:峨眉弟子被少林大力金刚指所杀
武当收到消息:少林弟子毫不会作出这种事情
峨眉收到消息:少林弟子毫不会作出这种事情

接下来给出这个例子的UML图,以下所示。

中介者模式的优缺点和使用场景
优势
符合迪米特原则,将原有的一对多的依赖变成了一对一的依赖,下降类间的耦合。

缺点
中介者会变得庞大且复杂,本来多个对象直接的相互依赖变成了中介者和多个同事类的依赖关系,同事类越多,中介者的逻辑就越复杂。

使用场景
中介者模式很容易实现呢,可是也容易误用,不要着急使用,先要思考你的设计是否合理。
当对象之间的交互变多时,为了防止一个类会涉及修改其余类的行为,可使用中介者模式,将系统从网状结构变为以中介者为中心的星型结构。

3.代理模式、外观模式和中介者模式对比

当咱们学完中介者模式是否是会以为和此前讲过的代理模式和外观模式有些相似呢?如今咱们一一来将它们进行对比。

代理模式和中介者模式
代理模式是结构型设计模式,它有不少种类型,主要是在访问对象时引入必定程度的间接性,因为有间接性,就能够附加多种的用途,好比进行权限控制。中介者模式则是为了减小对象之间的相互耦合。虽然网上有不少代理模式和中介者模式的对比,可是在我看来这二者实际上并无可比性,只是看起来有些相似罢了。
外观模式和中介者模式
外观模式主要是以封装和隔离为主要任务,中介者则是调停同事类之间的关系,所以,中介者具备部分业务的逻辑控制。他们之间的主要区别为:

  • 外观模式的子系统若是脱离外观模式仍是能够运行的,而中介者模式增长了业务逻辑,同事类不能脱离中介者而独自存在。
  • 外观模式中,子系统是不知道外观类的存在的,而中介者模式中,每一个同事类都知道中介者。
  • 外观模式将子系统的逻辑隐藏,用户不知道子系统的存在,而中介者模式中,用户知道同事类的存在。

github源码

参考资料
《大话设计模式》
《设计模式之禅》
《Android源码设计模式》


欢迎关注个人微信公众号,第一时间得到博客更新提醒,以及更多成体系的Android相关原创技术干货。
扫一扫下方二维码或者长按识别二维码,便可关注。

相关文章
相关标签/搜索