一起学设计模式 - 中介者模式

中介者模式(MediatorPattern)属于 行为型模式的一种,用一个 中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。

概述

在我们的生活中处处充斥着中介者,比如租房、买房、出国留学、找工作、旅游等等可能都需要那些中介者的帮助,同时我们也深受其害,高昂的中介费,虚假信息。 在地球上最大的中介者就是联合国了,它主要用来维护国际和平与安全、解决国际间经济、社会、文化和人道主义性质的问题。国与国之间的关系异常复杂,会因为各种各样的利益关系来结成盟友或者敌人,熟话说没有永远的朋友,也没有永远的敌人,只有永远的利益!所以国与国之间的关系同样会随着时间、环境因为利益而发生改变。在我们软件的世界也同样如此,对象与对象之间存在着很强、复杂的关联关系,如果没有类似于联合国这样的“机构”会很容易出问题的,譬如:

1、 对象与对象之间存在大量的关联关系,这样势必会导致系统的结构变得很复杂,同时若一个对象发生改变,我们也需要跟踪与之相关联的对象,同时做出相应的处理。

2、 对象之间的连接增加会导致对象可复用性降低。

3、 系统的可扩展性低。增加一个新的对象,我们需要在其相关连的对象上面加上引用,这样就会导致系统的耦合性增高,使系统的灵活性和可扩展都降低。

在前面我就知道如果两个类不必彼此通信,那么这两个类就不应当发生直接关联的关系。如果其中一个类需要调用另一个类中的方法,我们可以通过第三方来转发这个调用。所以对于关系比较复杂的系统,我们为了减少对象之间的关联关系,使之成为一个松耦合系统,我们就需要使用中介者模式。

通过中介者模式,我们可以将复杂关系的网状结构变成结构简单的以中介者为核心的星形结构,每个对象不再和它与之关联的对象直接发生相互作用,而是通过中介者对象来另一个对象发生相互作用。

UML结构图

模式结构

  • Mediator(抽象中介者): 定义了同事对象到中介者对象之间的接口
  • ConcreteMediator(具体中介者): 实现抽象中介者的方法,它需要知道所有的具体同事类,同时需要从具体的同事类那里接收信息,并且向具体的同事类发送信息。
  • Colleague(抽象同事类): 它定义各个同事类公有的方法,并声明了一些抽象方法来供子类实现,同时维持了一个对抽象中介者类的引用,其子类可以通过该引用来与中介者通信。
  • ConcreteColleague(具体同事类): 抽象同事类的子类;每个同事对象在与其他同事对象通信时,先与中介者通信,通过中介者来间接完成与其他同事类的通信;在具体同事类中实现了在抽象同事类中声明的抽象方法。

案例

以租房为例,这里中介机构充当租房者与房屋所有者之间的中介者。UML结构图:

UML图如下:

1.定义抽象中介者

interface Mediator {

    /**
     * 让对象之间通讯
     * @param content 传递的内容
     * @param person  传递的对象
     */
    void contact(String content, AbstractPerson person);

}

2.定义抽象同事类 AbstractPerson

abstract class AbstractPerson {

    protected String name;
    protected Mediator mediator;

    AbstractPerson(String name, Mediator mediator) {
        this.name = name;
        this.mediator = mediator;
    }

    public abstract void receiveMessage(String msg);

}

3.分别定义 房东租客类,继承抽象同事类

class HouseOwner extends AbstractPerson {

    HouseOwner(String name, Mediator mediator) {
        super(name, mediator);
    }

    public void contact(String message) {
        mediator.contact(message, this);
    }

    @Override
    public void receiveMessage(String message) {
        System.out.println("房主:" + name + ",获得信息:" + message);
    }
}

class Tenant extends AbstractPerson {

    Tenant(String name, Mediator mediator) {
        super(name, mediator);
    }

    public void contact(String message) {
        mediator.contact(message, this);
    }

    @Override
    public void receiveMessage(String message) {
        System.out.println("租客:" + name + ",获得信息:" + message);
    }
}

4.创建具体中介者,抽象的实现,用来协调各个同事之间调用

class MediatorStructure implements Mediator {

    private HouseOwner houseOwner;
    private Tenant tenant;

    public HouseOwner getHouseOwner() {
        return houseOwner;
    }

    public void setHouseOwner(HouseOwner houseOwner) {
        this.houseOwner = houseOwner;
    }

    public Tenant getTenant() {
        return tenant;
    }

    public void setTenant(Tenant tenant) {
        this.tenant = tenant;
    }

    @Override
    public void contact(String message, AbstractPerson person) {
        //如果是房主,则租房者获得信息
        if (person == houseOwner) {
            tenant.receiveMessage(message);
        } else {
            //反正则是房主获得信息
            houseOwner.receiveMessage(message);
        }
    }
}

5.创建客户端测试

public class Client {

    public static void main(String[] args) {
        //一个房主、一个租房者、一个中介机构
        MediatorStructure mediator = new MediatorStructure();

        HouseOwner owner = new HouseOwner("小唐", mediator);
        Tenant tenant = new Tenant("小李", mediator);

        mediator.setHouseOwner(owner);
        mediator.setTenant(tenant);

        tenant.contact("房东您好,请问还有三室两厅出粗吗.....");
        owner.contact("还有!你需要租吗?");

    }
}

6.运行结果

房主:小唐,获得信息:房东您好,请问还有三室两厅出粗吗.....
租客:小李,获得信息:还有!你需要租吗?

总结

  • 在中介者模式中通过引用中介者对象,将系统中有关的对象所引用的其他对象数目减少到最少。它简化了系统的结构,将系统由负责的网状结构转变成简单的星形结构,中介者对象在这里起到中转和协调作用。
  • 中介者类是中介者模式的核心,它对整个系统进行控制和协调,简化了对象之间的交互,还可以对对象间的交互进行进一步的控制。
  • 通过使用中介者模式,具体的同事类可以独立变化,通过引用中介者可以简化同事类的设计和实现。
  • 就是由于中介者对象需要知道所有的具体同事类,封装具体同事类之间相互关系,导致中介者对象变得非常复杂,系统维护起来较为困难。

优点

  • 简化了对象之间的关系,将系统的各个对象之间的相互关系进行封装,将各个同事类解耦,使系统成为松耦合系统。
  • 减少了子类的生成。
  • 减少各同事类的设计与实现。

缺点

  • 中介者会庞大,变得复杂难以维护。

JDK中应用

Mediator模式在事件驱动类应用中比较多,例如聊天、消息传递等等,需要有一个MessageMediator,专门负责request/reponse之间任务的调节。

JDK的具体应用:

- java.util.Timer
- java.util.concurrent.Executor#execute()
- java.util.concurrent.ExecutorService#submit()
- java.lang.reflect.Method#invoke()

说点什么

参考文献:http://www.cnblogs.com/JsonShare/p/7263876.html

全文代码:https://gitee.com/battcn/design-pattern/tree/master/Chapter15/battcn-mediator

本文分享自微信公众号 - battcn(battcn)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2017-12-04

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Java开发者杂谈

分布式改造剧集1

背景介绍 ​ 我所在的项目组,使用的技术一直是接近原始社会的:jdk1.6 + SpringMVC + hessian + Mybatis,当前最火的中间件技术...

30840
来自专栏Java架构沉思录

Kafka中的时间轮算法

简单说说时间轮吧,它是一个高效的延时队列,或者说定时器。实际上现在网上对于时间轮算法的解释很多,定义也很全,这里引用一下朱小厮博客里出现的定义:

16320
来自专栏晨星先生的自留地

关于一次渗透引发的一个php木马的分析

55450
来自专栏更流畅、简洁的软件开发方式

【自然框架】注册会员活动——第一份代码的修改建议(第一版)

  感谢“好坏”提供代码,这是我看过的比较不错的三层结构的代码了,业务层并不是直接调用DAL,而是有其自身的逻辑判断,并不是传声筒,很赞。 我对这份代码,按照自...

22960
来自专栏数说工作室

【SAS Says】基础篇:SAS宏初步

特别说明:本节【SAS Says】基础篇:SAS宏初步,用的是数说君学习《The little SAS book》时的中文笔记,我们认为这是打基础的最好选择。 ...

35140
来自专栏我的技术专栏

C++ 自由存储区是否等价于堆?

41550
来自专栏玩转JavaEE

MongoDB管道操作符(二)

上篇文章中我们已经学习了MongoDB中几个基本的管道操作符,本文我们再来看看其他的管道操作符。 ---- $group 基本操作 $group可以用来对文档进...

30360
来自专栏wOw的Android小站

[设计模式]之五:职责链模式

使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。

21520
来自专栏Spark学习技巧

Flink DataStream编程指南及使用注意事项。

Flink中的DataStream程序是对数据流进行转换的常规程序(例如,过滤,更新状态,定义窗口,聚合)。数据流的最初的源可以从各种来源(例如,消息队列,套接...

2.8K70
来自专栏Android 技术栈

java 常用十种设计模式示例归纳 | 已打包请带走

一个Demo,集合常用的十种设计模式,每个模式使用易被人们接受的案例讲述,按模式分包,使用设计模式前后对比,界面显示定义讲解,让你更深刻的了解每种设计模式。 ...

4.7K20

扫码关注云+社区

领取腾讯云代金券