zoukankan      html  css  js  c++  java
  • 《图解设计模式》读书笔记7-2 Mediator模式

    Mediator模式简介

    Mediator模式即中介者模式,可以像租房中介一样对比理解。

    模式来源:比如一个窗口程序里面包含按钮、复选框、文本框等角色,他们之间的状态可能相互关联:比如你必须勾选同意用户协议的复选框才能进行点击下一步按钮,即复选框同意按钮有关联关系。像这样的同一个页面有关联关系的部件可能很多,关联关系可能很复杂。如果这些按钮既要负责自己的显示,又要负责维护关联关系,职责就太多了,极易发生混乱而出错。

    此模式的关键作用是:职责分离,把各个部件中负责关联关系的部分提取出来,由一个中介统一管理。

    示例程序

    一个登录对话框,如图所示

    使用方式如下

    各种情况

    • 作为游客访问,禁用用户名和密码输入框

    • 作为用户登录,启用用户名输入框,如果没有输入用户名,则不启用密码框

    • 用户登录时,如果输入了用户名,则启用密码框

    • 用户登录时,如果用户名和密码的字符串长度都超过了4个字符,则OK按钮启用,否则不启用

    • Cancel按钮总是处于启用状态

    示例程序类图

    • Mediator是中介者接口,Colleague是组员接口,组员之间的关系由中介者维护。

    代码

    Mediator接口

    这个接口是中介者的抽象接口,具体的中介者会继承并实现它

    public interface Mediator {
        //生成组员方法
        public abstract void createColleagues();
        //组员状态改变后向中介报告
        public abstract void colleagueChanged();
    }
    

    Colleague接口

    此接口是组员的抽象接口,具体的组员接口实现它。

    • setMediator(Mediator mediator):设置中介。具体的组员内部会引用一个中介者,这个方法用来设置中介者。
    • setColleagueEnabled(boolean enabled):设置组员自己的状态。这个方法被中介者调用进而控制组员,enabled为true表示组员可用,否则表示组员不可用。
    public interface Colleague {
        //设置中介
        public abstract void setMediator(Mediator mediator);
        //设置自己的状态是(可用/不可用)
        public abstract void setColleagueEnabled(boolean enabled);
    }
    

    三个具体的Colleague

    • checkbox和textfield变化时需要通知中介,button不需要。
    • 每个组员有一份中介的引用,用于向中介报告自己的状态。
    //checkbox
    public class ColleagueCheckbox extends Checkbox implements ItemListener, Colleague {
        private Mediator mediator;
        public ColleagueCheckbox(String caption, CheckboxGroup group, boolean state) {  
            // 构造函数 
            super(caption, group, state);
        }
        @Override
        public void itemStateChanged(ItemEvent e) {             // 当状态发生变化时通知Mediator
            mediator.colleagueChanged();
        }
        @Override
        public void setMediator(Mediator mediator) {            // 保存Mediator
            this.mediator = mediator;
        }
        @Override
        public void setColleagueEnabled(boolean enabled) {      // Mediator下达启用/禁用指示
            setEnabled(enabled);
        }
    }
    
    //textfield
    public class ColleagueTextField extends TextField implements TextListener, Colleague {
        private Mediator mediator;
        public ColleagueTextField(String text, int columns) {   // 构造函数
            super(text, columns);
        }
        @Override
        public void setMediator(Mediator mediator) {            // 保存Mediator
            this.mediator = mediator;
        }
        @Override
        public void setColleagueEnabled(boolean enabled) {      // Mediator下达启用/禁用的指示
            setEnabled(enabled);
            setBackground(enabled ? Color.white : Color.DARK_GRAY);
        }
        @Override
        public void textValueChanged(TextEvent e) {             // 当文字发生变化时通知Mediator
            mediator.colleagueChanged();
        }
    }
    //button
    public class ColleagueButton extends Button implements Colleague {
        private Mediator mediator;
        public ColleagueButton(String caption) {
            super(caption);
        }
        @Override
        public void setMediator(Mediator mediator) {            // 保存Mediator
            this.mediator = mediator;
        }
        @Override
        public void setColleagueEnabled(boolean enabled) {      // Mediator下达启用/禁用的指示 
            setEnabled(enabled);
        }
    }
    

    具体的中介者

    本例中的中介包含了两个功能:1.生成组员 2.接收组员的通知并采取相应措施。

    public class LoginFrame extends Frame implements ActionListener, Mediator {
        private ColleagueCheckbox checkGuest;
        private ColleagueCheckbox checkLogin;
        private ColleagueTextField textUser;
        private ColleagueTextField textPass;
        private ColleagueButton buttonOk;
        private ColleagueButton buttonCancel;
    
        // 构造函数。
        // 生成并配置各个Colleague后,显示对话框。
        public LoginFrame(String title) {
            super(title);
            setBackground(Color.LIGHT_GRAY);
            // 使用布局管理器生成4×2窗格
            setLayout(new GridLayout(4, 2));
            // 生成各个Colleague
            createColleagues();
            // 游客、登录的单选按钮
            add(checkGuest);
            add(checkLogin);
            //用户名、密码的输入框
            add(new Label("Username:"));
            add(textUser);
            add(new Label("Password:"));
            add(textPass);
            //确认、取消的按钮
            add(buttonOk);
            add(buttonCancel);
            colleagueChanged();
            // 显示
            pack();
            show();
        }
    
        // 生成各个Colleague。
        @Override
        public void createColleagues() {
            // 生成游客、登录的单选按钮
            CheckboxGroup g = new CheckboxGroup();
            // 初始化窗口时默认选择游客按钮
            checkGuest = new ColleagueCheckbox("Guest", g, true);
            checkLogin = new ColleagueCheckbox("Login", g, false);
            // 生成用户名、密码两个文本框
            textUser = new ColleagueTextField("", 10);
            textPass = new ColleagueTextField("", 10);
            textPass.setEchoChar('*');
            // 生成确认、取消的两个按钮
            buttonOk = new ColleagueButton("Confirm");
            buttonCancel = new ColleagueButton("Cancel");
            // 设置Mediator
            checkGuest.setMediator(this);
            checkLogin.setMediator(this);
            textUser.setMediator(this);
            textPass.setMediator(this);
            buttonOk.setMediator(this);
            buttonCancel.setMediator(this);
            // 设置Listener
            checkGuest.addItemListener(checkGuest);
            checkLogin.addItemListener(checkLogin);
            textUser.addTextListener(textUser);
            textPass.addTextListener(textPass);
            buttonOk.addActionListener(this);
            buttonCancel.addActionListener(this);
        }
    
        @Override
        public void colleagueChanged() {
            //游客模式:用户名密码都不可填
            if (checkGuest.getState()) {
                textUser.setColleagueEnabled(false);
                textPass.setColleagueEnabled(false);
                buttonOk.setColleagueEnabled(true);
            }
            // 用户登录模式:用户名可填写,根据用户名文本框里填写的内容来确定 密码框和按钮 是否可用
            else {
                textUser.setColleagueEnabled(true);
                userpassChanged();
            }
        }
    
        private void userpassChanged() {
            //如果填写了用户名
            if (textUser.getText().length() > 0) {
                //可以填写密码
                textPass.setColleagueEnabled(true);
                //如果用户名和密码都超过了4个字符,符合要求,确认按钮才能启用
                if (textUser.getText().length() >= 4 && textPass.getText().length() >= 4) {     
                    buttonOk.setColleagueEnabled(true);
                } else {
                    buttonOk.setColleagueEnabled(false);
                }
            }
            //如果没有填写用户名,则密码和确定按钮都不显示
            else {
                textPass.setColleagueEnabled(false);
                buttonOk.setColleagueEnabled(false);
            }
        }
        @Override
        public void actionPerformed(ActionEvent e) {
            System.out.println("动作是:" + e.getActionCommand());
            System.exit(0);
        }
    }
    

    main函数

    public class Main {
        static public void main(String args[]) {
            new LoginFrame("中介者模式");
        }
    }
    

    Mediator模式角色和类图

    角色

    • Mediator 中介者角色,负责定义与Colleague角色进行通信和做出决定的接口。

    • ConcreteMediator 具体的中介者角色,实现Mediator角色的接口,负责做出决定。

    • Colleague 负责定义与Mediator进行通信的接口。

    • ConcreteColleague 负责实现Colleague定义的接口。

    模式类图

    思路拓展

    简单化

    这个模式最大的好处就是通过职责分离,将组件的显示逻辑控制分离。在组件数量少的时候,关联关系简单,中介者的代码看起来很麻烦,似乎没有必要,但一旦需求变更,组件的数量增加,它们之间的通信线路就会呈指数增长,复杂度大大增加。使用中介作为逻辑控制中心,增加功能和维护功能都会变得很容易。

    角色复用

    如果不使用中介者模式,显示和逻辑混在一起,很难复用。

    但实际上只是具体的业务逻辑难以被复用,显示用的组件是可以被复用的。

    所以该模式把两部分拆出来,为组件的复用提供了便利。

  • 相关阅读:
    javaweb 最简单的分页技术
    Jquery选择器小结
    JSON 初探
    C# GridView 的使用
    C# 操作数据库
    Java中String为什么是不可变
    Eclipse使用技巧小结
    Java File类方法使用详解
    JSP基础语法总结
    JSP取得绝对路径
  • 原文地址:https://www.cnblogs.com/qianbixin/p/11123032.html
Copyright © 2011-2022 走看看