简单化

一、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)。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容