中介者模式在JDK源码中的应用

行为型模式

目录

1、中介者模式(Mediator Pattern)

1.1 中介者模式UML图

1.2 日常生活中看中介者模式

1.3 Java代码实例

2、中介者模式在JDK源码中体现

3、中介者模式优缺点

3.1 优点

3.2 缺点

3.3 使用场景

3.4 注意事项


1、中介者模式(Mediator Pattern)

说起来也简单、好理解。生活中我们租房经常都是通过中介来实现的。一般租房要么是房东直租要么是中介。那么今天要讲的中介者模式和租房的这个中介是否有关系呢?当然是有点关系的。中介者模式是用来降低多个对象和类之间的通信复杂性。这种模式提供了一个中介类,这个类就来处理不同类之间的通讯。租房中介也是这个道理。复制与各个房东和租户之间的通讯。将多对多简化成了一对多的关系。我们下面来具体看看到底是怎么回事吧!

用来降低多个对象和类之间的通信复杂性。这种模式提供了一个中介类,该类通常处理不同类之间的通信,并支持松耦合,使代码易于维护。

  • 意图:用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
  • 主要解决:对象与对象之间存在大量的关联关系,这样势必会导致系统的结构变得很复杂,同时若一个对象发生改变,我们也需要跟踪与之相关联的对象,同时做出相应的处理。
  • 何时使用:多个类相互耦合,形成了网状结构。
  • 如何解决:将上述网状结构分离为星型结构。
  • 关键代码:对象 Colleague 之间的通信封装到一个类中单独处理。

1.1 中介者模式UML图

UML图如下:

1.2 日常生活中看中介者模式

例如:世界上各个国家的和平和安全,沟通和交流等等问题,如果各个国家都可以互相交互的话,容易造成混乱,关系复杂。这个时候联合国的作用就出现了,联合国作为一个中介对象来维护各个国家的和平和安全等等的工作。

  • 1、中国加入 WTO 之前是各个国家相互贸易,结构复杂,现在是各个国家通过 WTO 来互相贸易。
  • 2、机场调度系统。
  • 3、MVC 框架,其中C(控制器)就是 M(模型)和 V(视图)的中介者。

1.3 Java代码实例

这里以公司各部门之间交互,使用中介者(总经理)的方式来代码实现。

首先定义一个抽象中介者(Mediator)对象:这里使用一个接口来定义

//抽象中介者
public interface Mediator {
    void register(String dname,Department d);//将具体的同事类注册到中介者中,让中介者知道所有的同事。以便进行交互
    void command(String dname);//通过部门名称,发出命令
}

再定义一个抽象同事类(Colleague):仍然使用一个接口来定义

//抽象同事类:部门
public interface Department {
    void selfAction();//做本部门的事
    void outAction();//向总经理发出申请
}

然后可以开始定义具体的实现了,先定义抽象同事的具体实现(ConcreteColleague)

研发部:

//具体同事类:研发部
public class Development implements Department{
    private Mediator m;//中介者(总经理)
    //构造的时候将中介者构造进来
    public Development(Mediator m) {
        super();
        this.m = m;
        //ConcreteMediator(具体中介者对象):实现抽象中介者的方法
        //它需要知道所有具体同事类,并从具体同事接收消息,向具体同事对象发出命令。
        m.register("development", this);//将当前部门对象注册到中介者对象中,
    }
    @Override
    public void selfAction() {
        System.out.println("研发部:正在研发项目......");
    }
    @Override
    public void outAction() {
        System.out.println("研发部向总经理说:项目经费没了.....");
    }
}

财务部:

//具体同事类:财务部
public class Finacial implements Department{
    private Mediator m;//中介者(总经理)
    //构造的时候将中介者构造进来
    public Finacial(Mediator m) {
        super();
        this.m = m;
        //ConcreteMediator(具体中介者对象):实现抽象中介者的方法
        //它需要知道所有具体同事类,并从具体同事接收消息,向具体同事对象发出命令。
        m.register("finacial", this);//将当前部门对象注册到中介者对象中,
    }
    @Override
    public void selfAction() {
        System.out.println("财务部:会计正在核对财务......");
    }
    @Override
    public void outAction() {
        System.out.println("财务部向总经理说:钱很多,花不完.....");
    }
}

市场部:

//具体同事类:市场部
public class Market implements Department{
    private Mediator m;//中介者(总经理)
    //构造的时候将中介者构造进来
    public Market(Mediator m) {
        super();
        this.m = m;
        //ConcreteMediator(具体中介者对象):实现抽象中介者的方法
        //它需要知道所有具体同事类,并从具体同事接收消息,向具体同事对象发出命令。
        m.register("market", this);//将当前部门对象注册到中介者对象中,
    }
    @Override
    public void selfAction() {
        System.out.println("市场部:正在跑市场......");
    }
    @Override
    public void outAction() {
        System.out.println("市场部向总经理说:合同已搞定,需财务部报销.....");
        m.command("finacial");//通过总经理这个中介,向总经理发出申请,告知需要跟财务部交互报销经费
    }
}

注意这里!!!    m.command("finacial");     这里通过总经理这个中介者对象,向财务部发出了申请。

通过中介者对象和财务部交互而没有直接跟财务部打交道

定义具体的中介者(ConcreteMediator):总经理

//中介者的具体实现:总经理
public class President implements Mediator{
    //总经理也需要知道所有具体同事类
    private Map<String,Department> map = new HashMap<String,Department>();
    @Override
    public void register(String dname, Department d) {
        map.put(dname, d);//将同事注册到总经理的所有同事类容器中
    }
    @Override
    public void command(String dname) {
        map.get(dname).selfAction();//根据部门名称向具体的部门下命令
    }
}

现在开始测试:

市场部需要向财务部发出申请,这时候就可以通过中介者(总经理)来向财务部发出申请了。而不是直接调用财务部的方法

public static void main(String[] args) {
    Mediator m = new President();//构建中介者对象:总经理
    Market market = new Market(m);//构建市场部
    market.selfAction();
    market.outAction();//市场部和财务部交互
}

输出结果:

            市场部:正在跑市场......

            市场部向总经理说:合同已搞定,需财务部报销.....

            财务部:会计正在核对财务......

2、中介者模式在JDK源码中体现

打开 JDK 中的 Timer 类,查看 Timer 类的结构,会发现 Timer 类中有很多 schedule() 重载方法,如下图所示。

Timer类结构图

任意点开其中一个方法,会发现所有方法最终都调用了私有的 sched() 方法,源码如下。

public class Timer {
    ...
    public void schedule(TimerTask task, long delay) {
        if (delay < 0)
            throw new IllegalArgumentException("Negative delay.");
        sched(task, System.currentTimeMillis()+delay, 0);
    }
    ...

    private void sched(TimerTask task, long time, long period) {
        if (time < 0)
            throw new IllegalArgumentException("Illegal execution time.");

        // Constrain value of period sufficiently to prevent numeric
        // overflow while still being effectively infinitely large.
        if (Math.abs(period) > (Long.MAX_VALUE >> 1))
            period >>= 1;

        synchronized(queue) {
            if (!thread.newTasksMayBeScheduled)
                throw new IllegalStateException("Timer already cancelled.");

            synchronized(task.lock) {
                if (task.state != TimerTask.VIRGIN)
                    throw new IllegalStateException(
                        "Task already scheduled or cancelled");
                task.nextExecutionTime = time;
                task.period = period;
                task.state = TimerTask.SCHEDULED;
            }

            queue.add(task);
            if (queue.getMin() == task)
                queue.notify();
        }
    }
    ...
}

不论是什么样的任务加入到队列中,我们都把这个队列中的对象称为“同事”。查看 sched() 方法的源码可以看出,所有的任务(task)都放到了 Timer 类维护的 task 队列中,同事之间的通信都是通过 Timer 来协调完成的,所以,Timer 承担了中介者的角色,而 task 队列内的任务就是具体同事对象。

3、中介者模式优缺点

3.1 优点

  • 1、降低了类的复杂度,将一对多转化成了一对一。
  • 2、各个类之间的解耦。
  • 3、符合迪米特原则。

3.2 缺点

  1. 中介者会庞大,变得复杂难以维护。
  2. 新增一个对象类,需要修改抽象中介者和具体中介者类。

3.3 使用场景

  • 1、系统中对象之间存在比较复杂的引用关系,导致它们之间的依赖关系结构混乱而且难以复用该对象。
  • 2、想通过一个中间类来封装多个类中的行为,而又不想生成太多的子类。

3.4 注意事项

不应当在职责混乱的时候使用。

 

参考文章:

http://m.biancheng.net/view/8496.html

https://www.runoob.com/design-pattern/mediator-pattern.html

https://www.cnblogs.com/meet/p/5116432.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值