中介者模式——java设计模式(十九)

简介

中介者模式(Mediator Pattern):定义一个对象封装一系列对象的交互,使各对象之间无需显示的相互引用,从而使得其耦合松散,用户可以独立的改变他们之间的交互。

  • 系统之间引用关系复杂,耦合过度,需要将两两之间的引用转化为对象和中介者的引用,将系统的网络结构转化成星型结构。
  • 这样可以急剧减少关系的数量,保证对象结构上的稳定性,不会因为对象的引入导致大量的修改工作。
  • 是迪米特法则的应用。

结构和实现

  • 角色包括:
    • 抽象中介者:定义接口,声明各个同事之间的交互方法。
    • 具体中介者:抽象中介者子类,维持同事对象的引用,实现协调交互的方法。根据需要面向抽象同事类或者具体同事类编程。
    • 抽象同事类:定义各个同事类的公有方法,声明抽象方法供子类实现,维持抽象中介者的引用。
    • 具体同事类:抽象同事类的子类。
  • 中介者模式结构。
    180514.mediatro.png
  • 中介者承担的作用:
    • 中转(结构性):各同事通过中介者实现简介调用。
    • 协调(行为性):中介者根据自身逻辑处理各个同事的请求。

实例

  • 开发客户信息管理窗口,截面组件关系复杂。增加一个客户,需要在客户列表List中增加一项,在组合框ComboBox中增加一项。需要使用中介者模式处理复杂的组件交互。
    180514.info.png
  • 具体中介者,维持各个同事的引用,封装之间的交互。
public class ConcreteMediator extends Mediator {  
    //维持对各个同事对象的引用  
    public AddButton addButton;  
    public List list;  
    public UserNameTextBox userNameTextBox;  
    public ComboBox cb;  

    //封装同事对象之间的交互  
    public void componentChanged(Component c) {  
        //单击按钮  
        if(c == addButton) {  
            list.update();  
            cb.update();  
            userNameTextBox.update();  
        }  
        //从列表框选择客户  
        else if(c == list) {  
            cb.select();  
            userNameTextBox.setText();  
        }  
        //从组合框选择客户  
        else if(c == cb) {  
            cb.select();  
            userNameTextBox.setText();  
        }  
    }  
}  
  • 由于不同组件的方法并不完全相同,中介者没有针对抽象同事类编程,而是在具体中介者中维持具体同事类的引用。

扩展中介者和同事类

  • 增加显示当前用户总数的标签。方案如下:
    1. 增加Label组件,修改原有的具体中介者,增加对Label对象的引用,在componentChanged方法中增加与Label有关的逻辑。
    2. 增加Label组件,增加一个具体中介者的子类,增加对Label对象的引用,覆盖componentChanged方法在新方法中增加Label相关逻辑。
  • 增加Label之后的结构。
    180514.expand.png
  • 具体中介者子类。
//新增具体中介者类  
public class SubConcreteMediator extends ConcreteMediator {  
    //增加对Label对象的引用  
    public Label label;  

    public void componentChanged(Component c) {  
        //单击按钮  
        if(c == addButton) {  
            list.update();  
            cb.update();  
            userNameTextBox.update();  
            label.update(); //文本标签更新  
        }  
        //从列表框选择客户  
        else if(c == list) {  
            cb.select();  
            userNameTextBox.setText();  
        }  
        //从组合框选择客户  
        else if(c == cb) {  
            cb.select();  
            userNameTextBox.setText();  
        }  
    }  
}
  • 新增具体同事类,只需要继承抽象同事类,实现其方法。与同事类的交互通过新增具体中介者实现。
  • 新增具体中介者,只需要继承抽象中介者类,覆盖其中的方法,增加需要的引用。

优缺点和适用范围

  • 优点:
    • 简化对象交互。将网状结构转化为星形结构。
    • 解耦同事对象。可以独立的改变每一个同时和中介者,更好的符合开闭原则。
    • 减少子类生成。将多个对象之间的行为集中于中介者,扩展时只需继承中介者而不是继承各个同事类。
  • 缺点:
    • 中介者复杂。集中大量同事类之间的交互逻辑,难以维护。
  • 适用范围:
    • 对象之间引用复杂、混乱,难以理解。
    • 一个对象引用其他很多对象,并直接通信,导致对象难以复用。
    • 通过一个类封装多个类的交互行为而不愿生成过多子类。

jdk中的应用

  • Timer中在schedulexxx方法中通过TaskQueue协调各种TimerTask定时任务,Timer是中介者,TimerTask是同事类。
public class Timer {

    private final TaskQueue queue = new TaskQueue();

    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();
        }
    }
}
class TaskQueue {

    private TimerTask[] queue = new TimerTask[128];
}

猜你喜欢

转载自blog.csdn.net/qq_40369829/article/details/80370601
今日推荐