ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

中介者模式详解

2021-07-15 18:06:45  阅读:119  来源: 互联网

标签:String void 同事 模式 详解 中介 new public


1.简介

在现实生活中,常常会出现好多对象之间存在复杂的交互关系,这种交互关系常常是“网状结构”,它要求每个对象都必须知道它需要交互的对象。例如,每个人必须记住他(她)所有朋友的电话;而且,朋友中如果有人的电话修改了,他(她)必须让其他所有的朋友一起修改,这叫作“牵一发而动全身”,非常复杂。
如果把这种“网状结构”改为“星形结构”的话,将大大降低他们之间的“耦合性”,这时只要找一个“中介者”就可以了。如前面所说的“每个人必须记住所有朋友的电话”的问题,只要在网上建立一个每个朋友都可以访问的“通信录”就解决了。这样的列子还有很多,例如,你刚刚参加工作想租房,可以找“房屋中介”;或者,自己刚刚到一个陌生城市找工作,可以找“人才交流中心”帮忙。
在软件的开发过程中,这样的例子也很多,例如,在MVC框架中,控制器(C)就是模型(M)和视图(V)的中介者;还有大家常用的QQ聊天程序的“中介者”是QQ服务器。所有这些,都可以采用“中介者模式”来实现,它将大大降低对象之间的耦合性,提高系统的灵活性。

2.定义

中介者(Mediator)模式的定义:定义一个中介对象来封装一系列对象之间的交互,使原有对象之间的耦合松散,且可以独立地改变他们之间的交互。中介者模式又叫调停模式,它是迪米特法则的典型应用。

3.优点

  1. 类之间各司其职,符合迪米特法则。
  2. 降低了对象之间的耦合性,使得对象易于独立地被复用。
  3. 将对象间的一对多关联转变为一对一的关联,提高系统的灵活性,使得系统易于维护和扩展。

4.缺点

中介模式将原本多个对象直接的相互依赖变成了中介者和多个同事类的依赖关系。当同事类越多时,中介者就会越臃肿,变得复杂且难以维护。

5.结构

中介者模式实现的关键是找出“中介者”。
中介者模式的主要角色如下:

  1. 抽象中介者(Mediator)角色:它是中介者的接口,提供了同事对象注册与转发同事对象信息的抽象方法。
  2. 具体中介者(Concrete Mediator)角色:实现中介者接口,定义一个List来管理同事对象,协调各个同事角色之间的交互关系,因此它依赖于同事角色。
  3. 抽象同事类(Colleague)角色:定义同事类的接口,保存中介者对象,提供同事对象交互的抽象方法,实现所有相互影响的同事类的公共功能。
  4. 具体同事类(Concrete Colleague)角色:是抽象 同时类的实现者,当需要与其他同事对象交互时,由中介者对象负责后续的交互。

结构图如下:
在这里插入图片描述

6.应用场景

  1. 当对象之间存在复杂的网状结构关系而导致依赖关系混乱且难以复用时。
  2. 当想创建一个运行于多个类之间的对象,又不想生成新的子类时。

7.代码样例

1.简单样例

/**
 * 抽象中介类
 */
interface IMediator{
    void register(Colleague colleague);
    void relay(Colleague colleague);
}

/**
 * 具体中介类
 */
class ConcreteMediator implements IMediator{
    private List<Colleague> colleagues = new ArrayList<>();
    @Override
    public void register(Colleague colleague) {
        if(!colleagues.contains(colleague)){
            colleagues.add(colleague);
            colleague.setMediator(this);
        }
    }
    @Override
    public void relay(Colleague colleague) {
        for(Colleague ob : colleagues){
            if(!ob.equals(colleague)){
                ob.receive();
            }
        }
    }
}
/**
 * 抽象同事类
 */
abstract class Colleague{
    @Setter
    protected IMediator mediator;
    public abstract void receive();
    public abstract void send();
}

/**
 * 具体同事类A
 */
class ConcreteColleagueA extends Colleague{
    @Override
    public void receive() {
        System.out.println("具体同事类A收到请求!");
    }

    @Override
    public void send() {
        System.out.println("具体同事类A发出请求!");
        mediator.relay(this);
    }
}

/**
 * 具体同事类B
 */
class ConcreteColleagueB extends Colleague{
    @Override
    public void receive() {
        System.out.println("具体同事类B收到请求!");
    }

    @Override
    public void send() {
        System.out.println("具体同事类B发出请求!");
        mediator.relay(this);
    }
}
public class MediaPatternSimpleTest {
    public static void main(String[] args){
        IMediator mediator = new ConcreteMediator();
        Colleague colleagueA = new ConcreteColleagueA();
        Colleague colleagueB = new ConcreteColleagueB();

        mediator.register(colleagueA);
        mediator.register(colleagueB);

        colleagueA.send();

        System.out.println("----------------");

        colleagueB.send();
    }
}

2.应用实例

例:用中介者模式编写一个“韶关房地产交流平台”程序。
说明:韶关房地产交流平台是“房地产中介公司”提供给“卖方客户”与“买方客户”进行信息交流的平台,比较适合用中介者模式来实现。
首先,定义一个中介公司(Medium)接口,它是抽象中介者,它包含了客户注册方法register(Customer member)和信息转发方法relay(String from, String ad);再定义一个韶关房地产中介(EstateMedium)公司,它是具体中介者类,它包含了保存客户信息的List对象, 并实现了中介公司中的抽象方法。
然后,定义一个客户(Customer)类,它是抽象同事类,其中包含了中介者的对象,和发送信息的send(String ad)方法与接收信息的receive(String from, String ad)方法的接口,由于本程序是窗体程序,所以本类继承JPmme类,并实现动作时间的处理方法actionPerformed(ActionEvent e)。
最后,定义卖方(Seller)类和买方(Buyer)类,它们是具体同事类,是客户(Customer)类的子类,它们实现了父类中的抽象方法,通过中介者进行信息交流。
结构图如下:
在这里插入图片描述
代码样例:

/**
 * 抽象中介类:中介公司
 */
interface IMedium{
    /**
     * 客户注册
     * @param member
     */
    void register(Customer member);

    /**
     * 转发
     * @param from
     * @param ad
     */
    void relay(String from, String ad);
}

/**
 * 具体中介者:房地产中介
 */
class EstateMedium implements IMedium{
    private List<Customer> members = new ArrayList<>();
    @Override
    public void register(Customer member) {
        if(!members.contains(member)){
            members.add(member);
            member.setMedium(this);
        }
    }

    @Override
    public void relay(String from, String ad) {
        for(Customer ob : members){
            String name = ob.getName();
            if(!name.equals(from)){
                ob.receive(from, ad);
            }
        }
    }
}
/**
 * 抽象同事类:客户
 */
abstract class Customer extends JFrame implements ActionListener{
    @Setter
    protected IMedium medium;
    @Getter
    protected String name;
    JTextField sendText;
    JTextArea receiveArea;
    public Customer(String name){
        super(name);
        this.name = name;
    }
    void ClientWindow(int x, int y){
        Container cp;
        JScrollPane sp;
        JPanel p1, p2;
        cp = this.getContentPane();
        sendText = new JTextField(18);
        receiveArea = new JTextArea(10, 18);
        p1 = new JPanel();
        p1.setBorder(BorderFactory.createTitledBorder("接收内容:"));
        p1.add(receiveArea);
        sp = new JScrollPane(p1);
        cp.add(sp, BorderLayout.NORTH);
        p2 = new JPanel();
        p2.add(sendText);
        cp.add(p2, BorderLayout.SOUTH);
        sendText.addActionListener(this);
        this.setLocation(x, y);
        this.setSize(250, 330);
        this.setResizable(false);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
    }
    @Override
    public void actionPerformed(ActionEvent e){
        String tempInfo = sendText.getText().trim();
        sendText.setText("");
        this.send(tempInfo);
    }
    public abstract void send(String ad);
    public abstract void receive(String from, String ad);
}

/**
 * 具体同事类:卖方
 */
class Seller extends Customer{
    public Seller(String name) {
        super(name);
        ClientWindow(50, 100);
    }

    @Override
    public void send(String ad) {
        receiveArea.append("我(卖方)说:" + ad + "\n");
        //使滚动条滚动到最低端
        receiveArea.setCaretPosition(receiveArea.getText().length());
        medium.relay(name, ad);
    }

    @Override
    public void receive(String from, String ad) {
        receiveArea.append(from + "说:" + ad + "\n");
        receiveArea.setCaretPosition(receiveArea.getText().length());
    }
}

/**
 * 具体同事类:买方
 */
class Buyer extends Customer{
    public Buyer(String name) {
        super(name);
        ClientWindow(350, 100);
    }

    @Override
    public void send(String ad) {
        receiveArea.append("我(买方)说:" + ad + "\n");
        receiveArea.setCaretPosition(receiveArea.getText().length());
        medium.relay(name, ad);
    }

    @Override
    public void receive(String from, String ad) {
        receiveArea.append(from + "说:" + ad + "\n");
        receiveArea.setCaretPosition(receiveArea.getText().length());
    }
}
public class MediatorEstateMediumTest{
    public static void main(String[] args){
        IMedium medium = new EstateMedium();
        Customer memberA, memberB;
        memberA = new Seller("张三(卖方)");
        memberB = new Buyer("李四(买方)");
        medium.register(memberA);
        medium.register(memberB);
    }
}

运行结果:
在这里插入图片描述

3.应用模式的扩展

在实际开发中,通常采用以下两种方法来简化中介者模式,使开发变得更简单。

  1. 不定义中介者接口,把具体中介者对象实现为单例。
  2. 同事对象不持有中介者,而是在需要的时候直接获取中介者对象并调用。

结构图如下:
在这里插入图片描述
代码样例:

/**
 * 简单单例中介者
 */
class SimpleMediator{
    private static SimpleMediator simpleMediator = new SimpleMediator();
    private List<ISimpleColleague> colleagues = new ArrayList<>();
    private SimpleMediator(){}
    public static SimpleMediator getMedium(){
        return simpleMediator;
    }
    public void register(ISimpleColleague colleague){
        if(!colleagues.contains(colleague)){
            colleagues.add(colleague);
        }
    }
    public void relay(ISimpleColleague colleague){
        for(ISimpleColleague coll : colleagues){
            if(!coll.equals(colleague)){
                coll.receive();
            }
        }
    }
}

/**
 * 抽象同事类
 */
interface ISimpleColleague{
    void send();
    void receive();
}

class SimpleConcreteColleagueA implements ISimpleColleague{
    SimpleConcreteColleagueA(){
        SimpleMediator mediator = SimpleMediator.getMedium();
        mediator.register(this);
    }
    @Override
    public void send() {
        SimpleMediator mediator = SimpleMediator.getMedium();
        System.out.println("具体同事A发出请求!");
        mediator.relay(this);
    }

    @Override
    public void receive() {
        System.out.println("具体同事A收到请求!");
    }
}

class SimpleConcreteColleagueB implements ISimpleColleague{
    SimpleConcreteColleagueB(){
        SimpleMediator mediator = SimpleMediator.getMedium();
        mediator.register(this);
    }
    @Override
    public void send() {
        SimpleMediator mediator = SimpleMediator.getMedium();
        System.out.println("具体同事B发出请求!");
        mediator.relay(this);
    }

    @Override
    public void receive() {
        System.out.println("具体同事B收到请求!");
    }
}
public class SimpleMediatorPatternTest {
    public static void main(String[] args){
        ISimpleColleague colleagueA = new SimpleConcreteColleagueA();
        ISimpleColleague colleagueB = new SimpleConcreteColleagueB();

        colleagueA.send();
        System.out.println("------------------------");
        colleagueB.send();
    }
}

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

打开JDK中的Timer类,查看Timer类的结构,会发现Timer类中很多schedule()重载方法,如下图所示:
在这里插入图片描述
任意点开其中一个方法,会发现最终都调用了私有的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队列内的任务就是具体同事对象。

标签:String,void,同事,模式,详解,中介,new,public
来源: https://blog.csdn.net/d303577562/article/details/118723060

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有