Mediator - 中介者设计模式

30 阅读2分钟

什么是中介者设计模式?

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

中介者模式属于行为型模式。中介者在前端项目中有很广泛的应用,如多个组件同时监听同一个状态,一旦A组件修改了这个状态,需要主动通知其他若干个组件去重新渲染。Redux 是一个状态管理器,如上场景就可以把状态托管给 Redux,所有相关的组件去监听 Redux 的事件,如果状态变化了,则重新渲染。有组件需要去更新状态,则通过 Redux API dispatch 方法,把新的值传给 Redux 的 store。在这里我们能够看出,其实 Redux 扮演了中介者的角色,各个组件之间无需直接通讯,而是只面向 Redux,进而降低系统复杂度和组件间的耦合。

优缺点

优点:

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

缺点:

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

示例

类似前端的状态管理组件,后台常见的应用如消息队列,我们实现一个简单版本:

public class Component {
    private String name;
    private String msgGroup;
    private Mediator mediator;

    public Component(String name, String msgGroup, Mediator mediator) {
        this.name = name;
        this.msgGroup = msgGroup;
        this.mediator = mediator;
        new Thread(() -> listen()).start();
    }

    public void dispatch(String msg) {
        this.mediator.dispatch(this.msgGroup, msg);
    }

    private void listen() {
        while(true) {
            if (mediator != null) {
                final String msg = mediator.consume(this.msgGroup, this.name);
                if (msg != null) {
                    System.out.println(
                            String.format("[%s] received a msg from %s group: %s", this.name, this.msgGroup, msg));
                }
            }
        }
    }
}

static class Mediator {
    // 用于存储消息
    private volatile Map<String, List<String>> store = new ConcurrentHashMap<>();
    // 用于记录每个客户消费消息的index,避免重复消费
    private volatile Map<String, Map<String, Long>> consumerIdx = new HashMap<>();
    public void dispatch(String msgGroup, String message) {
        synchronized (this.getClass()) {
            if (!this.store.containsKey(msgGroup)) {
                this.store.put(msgGroup, new Vector<>());
            }
            store.get(msgGroup).add(message);
        }
    }

    public String consume(String msgGroup, String consumerName) {
        final List<String> msgQueue = store.get(msgGroup);
        synchronized (this.getClass()) {
            initIfNotExists(msgGroup, consumerName);
            final Long idx = consumerIdx.get(msgGroup).get(consumerName);
            if (msgQueue != null && msgQueue.size() > idx) {
                final String s = msgQueue.get((int) idx.longValue());
                this.consumerIdx.get(msgGroup).put(consumerName, idx + 1);
                return s;
            }
            return null;
        }
    }

    private void initIfNotExists(String msgGroup, String consumerName) {
        if (!this.consumerIdx.containsKey(msgGroup)) {
            final Map<String, Long> map = new HashMap<>();
            this.consumerIdx.put(msgGroup, map);
        }
        if (!this.consumerIdx.get(msgGroup).containsKey(consumerName)) {
            this.consumerIdx.get(msgGroup).put(consumerName, 0L);
        }
    }
}
// test
public static void main(String[] args) {
    final Mediator mediator = new Mediator();
    final String msgGroup = "MSG - 01";
    final Component componentA = new Component("A", msgGroup, mediator);
    final Component componentB = new Component("B", msgGroup, mediator);

    mediator.dispatch(msgGroup, "Hello world!");
    componentA.dispatch("Hello, This is A, nice to meet u");
    componentB.dispatch("This is B, nice to meet u too");
}

Output

[A] received a msg from MSG - 01 group: Hello world!
[B] received a msg from MSG - 01 group: Hello world!
[B] received a msg from MSG - 01 group: Hello, This is A, nice to meet u
[A] received a msg from MSG - 01 group: Hello, This is A, nice to meet u
[B] received a msg from MSG - 01 group: This is B, nice to meet u too
[A] received a msg from MSG - 01 group: This is B, nice to meet u too