【设计模式】中介者模式的目标是让对象的网状结构变成星形结构。

398 阅读5分钟

这是我参与8月更文挑战的第4天,活动详情查看:8月更文挑战

什么是中介者模式(Mediator)

概念

中介者模式(Mediator Pattern)属于行为型模式,中介者模式是为了解决对象之间相互引用的情况,通过中介者对象来解除这些对象之间的相互引用,让对象之间的通信交给中介者对象来完成,使得对象从网状结构转变成了星形结构,以此降低对象间的耦合程度。

image-20210611215238655

像我们在水群里聊天,我们可以把每个客户端当成一个对象,如果采用网状结构,那么就得每个客户端都得记录其他客户端的地址才行,那一个人想要加入这个水群就非常地困难,如果是采用星形结构,每个客户端都和一个服务端进行连接,服务端可以看作一个中介者,所有的客户端想要收发消息都得通过服务端,服务端会帮客户端转发消息,这样每个客户端想要加入水群,只需要找到这个服务端即可,这样就特别方便了。

月入1800水群笑哈哈

优点

  1. 符合迪米特法则,单一职责原则。由中介者来完成和其他对象的交互,对象无需知道和其他对象交互的过程。
  2. 减低了类的复杂程度。将对象一对多的关系装换成了一对一的关系,也有利于系统的维护和扩展。

总之就是减少了对象之间的交集。

小黄鸡打架 群殴

缺点

  1. 当中介者承担越来越多的责任时,会使系统变得复杂难以维护。

这也是无可厚非的,可以考虑新建其他类来降低中介者的责任。

原则

“+”代表遵守,“-”代表不遵守或者不相关

原则开放封闭单一职责迪米特里氏替换依赖倒置接口隔离合成复用
-++-+--

适用场景

  1. 对象之间呈现网状结构
  2. 想要通过一个类来封装多个对象的行为。

如何实现

想要实现中介者模式,需要以下四个对象:

  1. 中介者抽象类/接口:定义同事对象注册与转发信息的操作。
  2. 中介者实现类:实现中介者抽象类/接口,定义一个集合来管理同事对象。
  3. 同事抽象类:定义同事类的方法,依赖中介者对象。
  4. 同事类:实现同事抽象类,当需要和其他同事对象交互时,调用中介者对象。

类图

中介者模式的结构图

同事对象中需要包含中介者,中介者中包含所有同事对象。

例子

就照着上面水群的例子吧,写一个模拟群聊的代码。

类图

image-20210611171859143

代码

中介者接口

/**
 * Created on 2021/6/11.
 *
 * @author xuxiaobai
 */
public interface Server {
​
​
    /**
     * 注册客户端
     * @param client
     */
    void register(Client client);
​
    /**
     * 服务端帮忙转发
     * @param message
     * @param source
     */
    void relay(String message,Client source);
​
    /**
     * 注销客户端
     * @param client
     */
    void cancel(Client client);
}
​

中介者实现类

/**
 * 中介者
 * 服务端
 * Created on 2021/6/11.
 *
 * @author xuxiaobai
 */
public class ChatServer implements Server{
    List<Client> clients=new ArrayList();
​
​
    @Override
    public void register(Client client) {
        clients.add(client);
    }
​
    @Override
    public void relay(String message,Client source) {
        System.out.println("<接收情况");
        clients.forEach((item)->{
            if (source.equals(item)){
                return;
            }
            item.receiver(message);
        });
        System.out.println("接收情况>");
    }
​
    @Override
    public void cancel(Client client) {
        clients.remove(client);
    }
}

同事抽象类

/**
 * Created on 2021/6/11.
 *
 * @author xuxiaobai
 */
public abstract class Client {
    protected Server server;
​
    protected String username;
​
    public Client(Server server,String username){
        this.server=server;
        this.username=username;
    }
​
    /**
     * 修改服务器
     * @param server
     */
    public abstract void changeServer(Server server);
​
​
    /**
     * 接收消息
     * @param msg
     */
    public abstract void receiver(String msg);
​
​
    /**
     * 发送消息
     * @param msg
     */
    public abstract void send(String msg);
​
}

同事实现类

/**
 * 同事类
 * 客户端
 * Created on 2021/6/11.
 *
 * @author xuxiaobai
 */
public class ChatClient extends Client{
​
​
​
    public ChatClient(Server server, String username) {
        super(server, username);
        server.register(this);
    }
​
    public void changeServer(Server server){
        super.server.cancel(this);
        super.server=server;
        server.register(this);
    }
​
    @Override
    public void receiver(String msg) {
        System.out.println(username+"接收到了消息:"+msg);
    }
​
    @Override
    public void send(String msg) {
        System.out.println(username+"发送消息:"+msg);
        server.relay(this.username+"说"+msg,this);
    }
}

测试类

/**
 * 测试类
 * Created on 2021/6/11.
 *
 * @author xuxiaobai
 */
public class MediatorTest {
    public static void main(String[] args) {
        Server server=new ChatServer();
        //模拟客户端,加入服务器
        Client clientA=new ChatClient(server,"ClientA");
        Client clientB=new ChatClient(server,"ClientB");
        Client clientC=new ChatClient(server,"ClientC");
​
        //模拟通话
        clientA.send("hi");
        clientB.send("hello");
        clientA.send("我们说中文吧。");
        clientB.send("好。");
        /**
         * ClientA发送消息:hi
         * <接收情况
         * ClientB接收到了消息:ClientA说hi
         * ClientC接收到了消息:ClientA说hi
         * 接收情况>
         * ClientB发送消息:hello
         * <接收情况
         * ClientA接收到了消息:ClientB说hello
         * ClientC接收到了消息:ClientB说hello
         * 接收情况>
         * ClientA发送消息:我们说中文吧。
         * <接收情况
         * ClientB接收到了消息:ClientA说我们说中文吧。
         * ClientC接收到了消息:ClientA说我们说中文吧。
         * 接收情况>
         * ClientB发送消息:好。
         * <接收情况
         * ClientA接收到了消息:ClientB说好。
         * ClientC接收到了消息:ClientB说好。
         * 接收情况>
         *
         */
    }
}

这里简单地模式了一下客户端之间的通信,客户端都不是直接通信的,都需要通过server来转发自己的消息,有那么一点点抽象,可以多看看。

小胖子下班啦

如果想实现一个聊天室,可以去了解以下websocket协议,然后做一个聊天室,你会发现聊天室也是使用了中介者模式。

总结

中介者模式跟组合模式非常地相似,都是用一个类去管理集合,但组合模式是屏蔽掉整体组合对象和单个对象的区别,而中介者模式是解除对象间的复杂依赖。

在使用中介者模式时,需要注意类的职责划分,一旦职责没有划分明确,会提高系统的复杂程度,适得其反。

小黄鸡发射光波

——————————————————————————————

你知道的越多,不知道的就越多。

如果本文章内容有问题,请直接评论或者私信我。如果觉得我写得还不错的话,点个赞也是对我的支持哦

未经允许,不得转载!