中介模式

概述

《设计模式》一书中对于 “中介模式” 的意图描述如下:

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

具体来讲,就是在对象过多,并且这些对象之间的交互关系过于复杂的情况下,通过引入第三方 “中介” 来处理这些对象之间的交互关系

一般 “中介者模式” 的 UML 图如下所示:

mediator_pattern.png

一般会在以下场景中使用 “中介者模式”:

  • 一组对象以定义良好但复杂的方式进行通信,产生的相互依赖关系结构混乱并且难以理解
  • 一个对象引用其它很多对象并且直接与这些对象进行通信,导致难以复用该对象
  • 想要定制一个分布在多个类中的行为,但是又不想生成太多的子类

具体示例

以一个对话框的交互为例,假设现在有这样的一个对话框,它需要在用户选择相关的字体时自动地将所有的文本输入内容都换成这一类型的字体。同时,也存在一个复选框,需要用户在选择对应的内容后才能提交本次的内容。如果按照传统的开发模式,将这一行为固定在不同的组件类中,这也能达到这个目的,但是这些对象就无法复用了,如果以后需要重新设计一个新的对话框,那么就不得不重新定义相关的子类,这很明显是不可取的

通过中介者模式,我们可以将对话框的处理逻辑交给 Mediator 进行处理,而其它的组件只需要采取相应的行为即可

定义中介者的对象类型:

public interface Mediator {
    void showDialog(); // 显示对话框
    void widgetChanged(Widget widget); // 当存在组件发神改变时需要采取的行为
}

定义每个组件的公共接口 Widget

public interface Widget {
    void onChanged(); // 当部分组件发生变化时需要采取的行为
}

由于这里需要知道中介者的存在,因此我们需要定义一个抽象组件父类来完成这一感知操作:

public abstract class AbstractWidget implements Widget {
    private final Mediator mediator;
    
    public AbstractWidget(Mediator mediator) {
        this.mediator = mediator;
    }
    
    @Override
    public void onChanged() {
        mediator.widgetChanged(this); // 将组件的改变事件委托给中介对象进行处理
    }
}

之后,定义具体的组件来实现相关的组件行为:

// 选择框的具体实例类型
public class ListBox extends AbstractWidget {
    private final Item[] items = new Items[]{};
    private int index; // 当前选择的条目
    
    public ListBost(Mediator mediator) {
        super(mediator);
    }
    
    public Item selected() {
        // 获取当前选择的条目
        return  items[index];
    }
}

// 文本框组件的具体实例类型
public class TextField extends AbstractWidget {
    private String content;
    
    public TextField(Mediator mediator) {
        super(mediator);
    }
    
    public String currentContent() {
        // 获取当前文本框的输入内容
        return content;
    }
    
    public void setContent(String content) {
        this.content = content;
    }
}

// 按钮组件的具体行为
public class Button extends AbstractWidget {
    
    private boolean clickedAble = false;
    
    public Button(Mediator mediator) {
        this.mediator = mediator;
    }
    
    public void click() {
        // 点击按钮时的具体行为
    }
    
    public void setClickedAble(boolean flag) {
        this.clickedAble = flag; // 设置是否可点击
    }
    
    public boolean clickedAble() {
        return this.clickedAble;
    }
}

现在,已经定义了部分具体的组件实例对象,需要定义具体的中介者来协调它们之间的交互关系:

public class SimpleMediator implements Mediator {
    private final ListBox listBox;
    private final TextField textField;
    private final Button button;
    
    public SimpleMediator() {
        this.listBox = new ListBox(this);
        this.textField = new TextField(this);
        this.button = new Button(this);
    }
    
    @Override
    public void showDialog() {
        // 省略组件的布局代码实现
    }
    
    @Override
    public void widgetChanged(Widget widget) {
        if (widget == listBox) {
            this.textField.setContent(listBox.selected().content());
            this.button.setClickedAble(true);
        } else if (widget == TextField) {
            this.textField.setContent(getInput());
        } else {
            if (this.clickedAble()) {
                this.button.click();
            }
        }
    }
}

总结

中介者模式看起来和外观模式很像,这两者的最大区别是外观模式只是对子系统的抽象,为子系统提供了一个更为方便的接口,这个接口是单向的,也就是说,具体内部的组件不需要知道和其它组件的协作关系;而中介者模式则提供了各个组件之间协作行为,这些行为可以是多向的


参考:

[1] 《设计模式—可复用面向对象基础》

posted @ 2023-04-10 21:00  FatalFlower  阅读(22)  评论(0编辑  收藏  举报