简单化

一、Facade 模式

1. 需求

一个用于从邮件地址中获取用户名字的数据库类,一个用于编写html 文件的类,以及一个半阳 facade 角色并提供高层接口API 的类。

2. UML

image.png

3. Code

大家看明白模式的设计思路就好,但是编码的示例比较古老,就不推荐大家学习了。
文件的目录结构:


image.png

3.1 DataBase 模拟从数据库中获取数据信息

/**
 * @author CSZ
 */
public class DataBase {
    private DataBase() {
    }
    public static Properties getProperties(String dbname){
        String filename =  dbname + ".properties";
        Properties properties = new Properties();
        try {
            properties.load(new FileInputStream(filename));
        }catch (IOException e){
            e.printStackTrace();
        }
        return properties;
    }
}

3.2 HtmlWriter 用于编写 html

/**
 * @author CSZ
 */
public class HtmlWriter {

    private Writer writer;
    public HtmlWriter(Writer writer) {
        this.writer = writer;
    }
    public void title(String title) throws IOException{
        writer.write("<html>");
        writer.write("<head>");
        writer.write("<title>" + title +"</title>");
        writer.write("</head>");
        writer.write("<body>\n");
        writer.write("<h1>" + title + "</h1>/n");
    }
    public void paragraph(String msg) throws IOException{
        writer.write("<p>" + msg + "</p>\n");
    }
    public void link(String href,String caption) throws IOException{
        paragraph("<a href=\"" + href + "\">" + caption + "</a>");
    }
    public void mailto(String mailaddr,String username)throws IOException{
        link("mailto:" + mailaddr,username);
    }
    public void close() throws IOException{
        writer.write("</body>");
        writer.write("</html>/n");
        writer.close();
    }
}

3.3 PageMaker 最终组装,也是 facade 的体现

/**
 * @author CSZ
 */
public class PageMaker {
    private PageMaker(){}
    public static void makeWelcomePage(String mailaddr,String filename){
        try {
            Properties maildata = DataBase.getProperties("maildata");
            String username = maildata.getProperty(mailaddr);
            HtmlWriter writer = new HtmlWriter(new FileWriter(filename));
            writer.title("Welcome to" + "username" + "'s page");
            writer.paragraph(username + "欢迎来到" + username + "的主页");
            writer.paragraph("等着你的邮件");
            writer.mailto(mailaddr,username);
            writer.close();
            System.out.println(filename + "is created for" + mailaddr + "(" + username + ")");
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}

3.4 模拟的数据库文件

qqqq@qq.com=qqqq
wangyi@wangyi.com=wangyi
google@gmail.com=google
apple@apple.com=apple

3.5 测试类

/**
 * @author CSZ
 */
public class MainTest {
    public static void main(String[] args) {
        PageMaker.makeWelcomePage("apple@apple.com","welcome.html");
    }
}

总结与思考

  1. 这种设计模式的作用:个人理解着很像我们常用的 工具类,StringUtils BeanUtils 等等,这样就减少了我们呢对于 接口API 的调用。


    image.png
  2. 当程序中,我们需要判断是否包含空格时,我们可以自己写一个方法,逻辑跟里面的逻辑也会差不多,但是如果他们已经提供好了现成的方法,我们直接调用是不是更加简单。这样我们本来需要调用 n 个工具包中的方法,并且编写逻辑,而现在我们只需要直接调用 contiansWhitespace 就可以了。
  3. 再进一步讲,在设计之初的时候,他们可能设计好了许多内在的关联关系,调用逻辑。但是作为使用者的你,可能并不知道他们做了怎样的优化,那么干脆提供给你一个他们已经实现好的复合逻辑,帮你判断了一些极端情况,而且有更高的执行效率。
  4. 反过来讲,书中也提出了,作为程序员,我们不喜欢利用这种模式做设计,原因是,如果我们的设计有漏洞,那么调用者就会遭殃,干脆就散落一些原子方法在类中。
  5. 另一个问题就是我们的类,字段,方法的暴露问题:如果我们暴露了太多,当我们作为设计者,想再修改这个类的内部就会很吃力,因为,别人能够看到的方法,别人可能调用哦,项目不是你一个人再做,一个开源的项目,你一个变动,可能很多项目就无法运行了,这是不合理的。
  6. 再代码的关键处,我们使用这种模式可以递归调用 Facade 模式,即 Facade 模式中封装的又是 Facade 模式的集合。


二、Mediator 模式

1. 说明:

image.png

2. 场景

image.png

设计一个会因为情况变动而变动的窗口。

3. UML

image.png

4. Code

4.1 Mediator

/**
 * 用于声明仲裁者身份
 * @author CSZ
 */
public interface Mediator {

    /**
     * 用于生成 Mediator 要管理的组员
     */
    public abstract void createColleagues();

    /**
     * 用于组员向仲裁者报告情况
     */
    public abstract void colleagueChanged();
}

4.2 Colleague

/**
 * 用于声明组员身份
 * @author CSZ
 */
public interface Colleague {

    /**
     * 向仲裁者进行报告的组员的接口,由具体组员实现
     */
    public abstract void setMediator(Mediator mediator);

    /**
     * 再根据所有组员的情况得出结论后,给每个组员指定要求
     */
    public abstract void setColleagueEnabled(boolean enabled);
}

4.3 ColleagueButton (组员)

/**
 * 组员1
 * @author CSZ
 */
public class ColleagueButton extends Button implements Colleague{

    private Mediator mediator;

    public ColleagueButton(String label) throws HeadlessException {
        super(label);
    }

    @Override
    public void setMediator(Mediator mediator) {
        this.mediator = mediator;
    }

    @Override
    public void setColleagueEnabled(boolean enabled) {
        setEnabled(enabled);
    }
}

4.4 ColleagueCheckbox (组员)

/**
 * 组员2
 * @author CSZ
 */
public class ColleagueCheckbox extends Checkbox implements ItemListener,Colleague{

    private Mediator mediator;

    public ColleagueCheckbox(String label, boolean state, CheckboxGroup group) throws HeadlessException {
        super(label, state, group);
    }

    @Override
    public void setMediator(Mediator mediator) {
        this.mediator = mediator;
    }

    @Override
    public void setColleagueEnabled(boolean enabled) {
        setEnabled(enabled);
    }

    @Override
    public void itemStateChanged(ItemEvent e) {
        mediator.colleagueChanged();
    }
}

4.5 ColleagueTextFiled (组员) 其他组员类似,在最后一个组员中说明方法作用

/**
 * 组员3
 * @author CSZ
 */
public class ColleagueTextFiled extends TextField implements TextListener,Colleague{
    private Mediator mediator;

    public ColleagueTextFiled(String text, int columns){
        super(text, columns);
    }

    @Override
    public void setMediator(Mediator mediator) {
        this.mediator = mediator;
    }

    // 在仲裁者给出的意见,要求该成员调用下面方法,完成响应
    @Override
    public void setColleagueEnabled(boolean enabled) {
        setEnabled(enabled);
        setBackground(enabled?Color.white:Color.lightGray);
    }

    // 当文字域中发生改变,被监听到,去找仲裁者仲裁
    @Override
    public void textValueChanged(TextEvent e) {
        mediator.colleagueChanged();
    }
}

4.6 LoginFrame (仲裁者)

/**
 * 类声明部分,通过实现 Mediator 来说明自己将担任仲裁者的身份
 * @author CSZ
 */
public class LoginFrame extends Frame implements ActionListener,Mediator {

    // 这里内部属性就是所有仲裁者小组下的员工
    private ColleagueCheckbox checkGuest;
    private ColleagueCheckbox checkLogin;
    private ColleagueTextFiled textUser;
    private ColleagueTextFiled textPass;
    private ColleagueButton buttonOk;
    private ColleagueButton buttonCancel;

    // 构造方法将所有的组件创建
    public LoginFrame(String title) throws HeadlessException {
        super(title);
        setBackground(Color.lightGray);
        setLayout(new GridLayout(4,2));
        // 实现 Mediator 就要指明谁是你的员工
        createColleagues();
        add(checkGuest);
        add(checkLogin);
        add(new Label("Username:"));
        add(textUser);
        add(new Label("Password:"));
        add(textPass);
        add(buttonOk);
        add(buttonCancel);
        colleagueChanged();
        pack();
        show();
    }

    // 对于 Mediator 来说要指明员工
    @Override
    public void createColleagues() {
        // 类似构建 form 表单
        CheckboxGroup checkboxGroup = new CheckboxGroup();
        checkGuest = new ColleagueCheckbox("Guest", true, checkboxGroup);
        checkLogin = new ColleagueCheckbox("Login", false, checkboxGroup);
        textUser = new ColleagueTextFiled("", 10);
        textPass = new ColleagueTextFiled("", 10);
        textPass.setEchoChar('*');
        buttonOk = new ColleagueButton("OK");
        buttonCancel = new ColleagueButton("Cancel");
        // 对于每个员工来说他们要重写 setMediator 方法来指定他们的组长
        checkGuest.setMediator(this);
        checkLogin.setMediator(this);
        textUser.setMediator(this);
        textPass.setMediator(this);
        buttonOk.setMediator(this);
        buttonCancel.setMediator(this);
        // 为了程序的效果,添加监听器
        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);
            buttonOk.setColleagueEnabled(textPass.getText().length() > 0);
        }else {
            textPass.setColleagueEnabled(false);
            buttonOk.setColleagueEnabled(false);
        }
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println(e.toString());
        System.exit(0);
    }
}

4.7 测试类

/**
 * @author CSZ
 */
public class MainTest {
    public static void main(String[] args) {
        new LoginFrame("Mediator Sample");
    }
}

5. 分析与总结

image.png
  1. 这个设计模式还是很有趣的,大家可以直接将我的代码拷过去,不要在乎java.awt 的实现细节。还是把关注点放在思想上。
  2. 问题就出在这里,思想的核心在于,牵一发而动全身,我们对组件中每个位置的修改,都会导致全盘的逻辑都需要调整,这就是关键,试想一下,如果我们不用这个模式,那么我们是不是要把所有的情况全部在if-else 中体现出来,比如 A开,B开,C开,所以 ok 开,cancle开,A 开,B开,C不开,所以ok不开,cancle开。。。这样逻辑上重复,臃肿的代码就在 ABC三个类中。现在呢,我们通过仲裁者的模式,当ABC中任意一个变动,我们本身都不直接处理,我们将所有的情况综合起来,汇报交给仲裁者,仲裁者根据一套逻辑,直接指明,ok 和 cancle 的状态,(其实,仲裁者会把每个人的状态都做规定,并且每个人都会执行,只是在这里我们假设关注 ok cancle状态)。
  3. 另外,一个组员跑路了,我们可以用新的组员来补充,或者我们简化团队,但是,项目经理跑路了,项目可能就凉了,望周知(bushi /doge)。
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容