zoukankan      html  css  js  c++  java
  • 8、Builder 建造者模式 组装复杂的实例 创造型模式

    1、什么是Builder模式

    定义:

    将一个复杂对象的构建与表示相分离,使得同样的构建过程可以创建不同的表示。大白话就是,你不需要知道这个类的内部是什么样的,只用把想使用的参数传进去就可以了,达到了解耦的目的。

    使用场景:

    (1) 相同的方法,不同的执行顺序,产生不同的事件结果时。 (2) 多个部件或零件,都可以装配到一个对象中。但是产生的运行结果又不相同时。 (3) 产品类非常复杂,或者产品类中的调用顺序不同产生了不同的作用,这个时候使用建造者模式非常合适。 (4) 当初始化一个对象特别复杂,如参数多,且很多参数都具有默认值时。

    2、示例

    类的一览表:

    image-20200720162210397

    示例类图:

    image-20200720162156254

    定义Builder接口

     package cn.design.create.builder;
     
     /**
      * @author lin
      * @version 1.0
      * @date 2020-07-20 14:15
      * @Description TODO
      */
     public interface Builder {
     
         void makeTitle(String title);
     
         void makeString(String str);
     
         void makeItems(String[] item);
     
         void close();
     }
     

    定义HtmlBuilder类

     package cn.design.create.builder;
     
     import java.io.FileWriter;
     import java.io.IOException;
     import java.io.PrintWriter;
     
     /**
      * @author lin
      * @version 1.0
      * @date 2020-07-20 15:58
      * @Description TODO
      */
     public class HtmlBuilder implements Builder {
         //文件名
         private String filename;
         //用于编写文件的PrintWriter
         private PrintWriter writer;
     
         @Override
         public void makeTitle(String title) {
             // HTML文件的标题
             //将标题作为文件名
             filename = title + ".html";
             try {
                 // 生成PrintWriter
                 writer = new PrintWriter(new FileWriter(filename));
            } catch (IOException e) {
                 e.printStackTrace();
            }
             writer.println("<html><head><title>" + title + "</title></head><body>");
             //输出标题
             writer.println("<h1>" + title + "</h1>");
        }
     
         @Override
         public void makeString(String str) {
             // HTML文件中的字符串
             //用<p>标签输出
             writer.println("<h4>" + str + "</h4>");
        }
     
         @Override
         public void makeItems(String[] items) {
             // HTML文件中的条目
             writer.println("<ul>");
             //用<ul>和<li>输出
             for (int i = 0; i < items.length; i++) {
                 writer.println("<li>" + items[i] + "</1i>");
            }
             writer.println("</ul>");
        }
     
         @Override
         public void close() {
             //完成文档
             writer.println("</body></html>");
             //关闭标签
             writer.close();
             //关闭文件
        }
     
         public String getResult() {
             //编写完成的文档
             //返回文件名
             return filename;
        }
     }
     

    定义TextBuilder类

     package cn.design.create.builder;
     
     /**
      * @author lin
      * @version 1.0
      * @date 2020-07-20 15:53
      * @Description TODO
      */
     public class TextBuilder implements Builder {
         private StringBuffer buffer = new StringBuffer();
     
         //又档内容保存在该子段中
         @Override
         public void makeTitle(String title) {
             //纯文本的标题
             buffer.append("========================= "); //装饰线
             //为标题添加「」
             buffer.append("「" + title + "」 ");
        }
     
         @Override
         public void makeString(String str) {
             //纯文本的字符串.
             //为字符串添加■
             buffer.append(" ■" + str + " ");
        }
     
         @Override
         public void makeItems(String[] items) {
             //纯文本的条目
             for (int i = 0; i < items.length; i++) {
                 //为条目添加.
                 buffer.append(" ● " + items[i] + " ");
            }
        }
     
         @Override
         public void close() {
             //完成文档
             // 装饰线
             buffer.append("======================== ");
        }
     
         public String getResult() {
             //完成的文档
             //将StringBuffer变换为String
             return buffer.toString();
        }
     }

    定义Director类

     package cn.design.create.builder;
     
     /**
      * @author lin
      * @version 1.0
      * @date 2020-07-20 14:18
      * @Description TODO
      */
     public class Director {
         private Builder builder;
     
         public Director(Builder builder) {
             //因为接收的参数是Builder类的子类
             //所以可以将其保存在builder字段中
             this.builder = builder;
        }
     
         public void construct() {
             //编写文档
             //标题
             builder.makeTitle("Greeting");
             //字符串
             builder.makeString("从早上至下午");
             //条目
             builder.makeItems(new String[]{
                     "早上好。",
                     "下午好。",
            });
             //其他字符串
             builder.makeString("晚上");
             //其他条目
             builder.makeItems(new String[]{
                     "晚上好。",
                     "晚安。",
                     "再见。",
            });
             //完成文档
             builder.close();
        }
     }

    定义测试BuilderMain类

     package cn.design.create.builder;
     
     /**
      * @author lin
      * @version 1.0
      * @date 2020-07-20 13:53
      * @Description TODO
      */
     public class BuilderMain {
         public static void main(String[] args) {
             if (args.length != 1) {
                 usage();
                 System.exit(0);
            }
             if (args[0].equals("plain")) {
                 TextBuilder textbuilder = new TextBuilder();
                 Director director = new Director(textbuilder);
                 director.construct();
                 String result = textbuilder.getResult();
                 System.out.println(result);
            } else if (args[0].equals("html")) {
                 HtmlBuilder htmlbuilder = new HtmlBuilder();
                 Director director = new Director(htmlbuilder);
                 director.construct();
                 String filename = htmlbuilder.getResult();
                 System.out.println(filename + "文件编写完成。");
            } else {
                 usage();
                 System.exit(0);
            }
        }
     
         public static void usage() {
             System.out.println("Usage: java Main plain 编写纯文本文档");
             System.out.println("Usage: java Main html 编写HTML文档");
        }
     
     }
     

    运行结果:

    plain:

     =========================
     「Greeting」
      ■从早上至下午
      ● 早上好。
      ● 下午好。
      ■晚上
      ● 晚上好。
      ● 晚安。
      ● 再见。
     ========================

    html:

    image-20200720162537693

    3、Builder模式中的角色

    类图:

    image-20200720162648739

    角色说明:

    ◆ Builder (建造者)

    Builder角色负责定义用于生成实例的接口( API )。Builder 角色中准备了用于生成实例的方法。在示例程序中,由Builder类扮演此角色。

    ◆ ConcreteBuilder (具体的建造者)

    ConcreteBuilder角色是负责实现Builder角色的接口的类(API)。这里定义了在生成实例时实际被调用的方法。此外,在ConcreteBuilder角色中还定义了获取最终生成结果的方法。在示例程序中,由TextBuilder类和HTMLBui lder类扮演此角色。

    ◆ Director (监工)

    Director角色负责使用Builder角色的接口( API)来生成实例。它并不依赖于ConcreteBuilder角色。为了确保不论ConcreteBuilder角色是如何被定义的,Director 角色都能正常工作,它只调用在Builder角色中被定义的方法。在示例程序中,由Director类扮演此角色。

    ◆Client(使用者)

    该角色使用了Builder 模式中,Builder 模式并不包含Client角色。在示例程序中,由Main类扮演此角色。

    4、相关的设计模式对比

    ◆Template Method模式

    在Builder模式中,Director 角色控制Builder角色。 在Template Method模式中,父类控制子类。

    ◆Composite模式

    有些情况下Builder模式生成的实例构成了Composite模式。

    ◆Abstract Factory模式

    Builder模式和Abstract Factory模式都用于生成复杂的实例。

    ◆Facade模式

    在Builder模式中,Director 角色通过组合Builder角色中的复杂方法向外部提供可以简单生成实例的接口( API)(相当于示例程序中的construct方法)。 Facade模式中的Facade角色则是通过组合内部模块向外部提供可以简单调用的接口( API)。

    5、小结

    为了灵活构造复杂对象,该对象会有多个成员变量,在外部调用的时候,不需要或者不方便一次性创建出所有的成员变量,在这种情况下,使用多个构造方法去构建对象,很难维护,这时候Builder设计模式解决这个问题,进行buid()方法中创建对象,并且将builder传入,该builder中,维护了传入对象的成员变量。

    优点:

    我可以不必知道你的内部构造是怎样的,我可以直接使用Builder建造自己需要的客户端;代码清晰,易维护,易扩展;将构造和表示分离,降低耦合 缺点:

    代码也可能不清晰,不易维护(怎么说:比如你的客户端实现了很多接口,当你每当修改接口的时候,每次都要对应修改你的客户端);使用不恰当消耗内存

    6、Main方法如何为args传参

     参数举例: 123 456 abc def 
     
     1. 编译器idea的使用方式:
        在 main 的 启动配置中 ,在程序参数中 填入自己需要的值
         
     2. 黑窗口的使用方式:
        不使用包路径, 大家都会. javac XXX.java 执行 java XXX abc def 123
        使用包路径,则要注意, javac -d . XXX.java 执行 java cn.**.XXX 123 456

    第一种参考如下:

    image-20200720163541134

    第二种参考如下:

     javac -d . cn.fagejiang.Test.java
     java cn.fagejiang.Test plain

     

    公众号发哥讲

    这是一个稍偏基础和偏技术的公众号,甚至其中包括一些可能阅读量很低的包含代码的技术文,不知道你是不是喜欢,期待你的关注。

    代码分享

    https://gitee.com/naimaohome

    微信公众号 点击关于我,加入QQ群,即可获取到代码以及高级进阶视频和电子书!!

    img

    如果你觉得文章还不错,就请点击右上角选择发送给朋友或者转发到朋友圈~

    ● 扫码关注我们

    据说看到好文章不推荐的人,服务器容易宕机!

    本文版权归 发哥讲博客园 共有,原创文章,未经允许不得转载,否则保留追究法律责任的权利。

     

     

  • 相关阅读:
    javascript中的"x != x"
    javascript中!=、!==、==、===操作符总结
    解决vscode格式化vue文件出现的问题
    js属性对象的hasOwnProperty方法
    JavaScript对象的valueOf()方法
    mac通过自带的ssh连接Linux服务器并上传解压文件
    基于ElementUI的网站换主题的一些思考与实现
    vue-cli的webpack模版项目配置解析
    CSS3标准盒模型还是IE怪异模型box-sizing属性的应用设置
    Windows上安装nodejs版本管理器nvm
  • 原文地址:https://www.cnblogs.com/naimao/p/13353493.html
Copyright © 2011-2022 走看看