1、什么是Builder模式

定义:

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

使用场景:

(1) 相同的方法,不同的执行顺序,产生不同的事件结果时。

(2) 多个部件或零件,都可以装配到一个对象中。但是产生的运行结果又不相同时。

(3) 产品类非常复杂,或者产品类中的调用顺序不同产生了不同的作用,这个时候使用建造者模式非常合适。

(4) 当初始化一个对象特别复杂,如参数多,且很多参数都具有默认值时。

2、示例

类的一览表:

示例类图:

定义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("=========================\n"); //装饰线
       //为标题添加「」
       buffer.append("「" + title + "」\n");
  }    @Override
   public void makeString(String str) {
       //纯文本的字符串.
       //为字符串添加■
       buffer.append(" ■" + str + "\n");
  }    @Override
   public void makeItems(String[] items) {
       //纯文本的条目
       for (int i = 0; i < items.length; i++) {
           //为条目添加.
           buffer.append("\t● " + items[i] + "\n");
      }
  }    @Override
   public void close() {
       //完成文档
       // 装饰线
       buffer.append("========================\n");
  }    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:

3、Builder模式中的角色

类图:

角色说明:

◆ 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

第一种参考如下:

第二种参考如下:

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

发哥讲

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

● 扫码关注公众号,  转载请备注来源,和链接

最新文章

  1. HackerRank &quot;Flatland Space Stations&quot;
  2. Asp.Net MVC4入门指南(4):添加一个模型
  3. 【日常笔记】java spring 注解读取文件
  4. MJExtension框架介绍
  5. 【Win10】解决 模拟器调试手机 错误-&gt; 引导阶段... 无法找到指定路径......\2052\msdbgui.dll
  6. HDU 1240 (简单三维广搜) Asteroids!
  7. Xmanager Enterprise Linking VM Redhat Linux AS4.7 X64&ndash;Server Configuration
  8. Linux CPU数量判断,通过/proc/cpuinfo.
  9. 获取客户端IP地址经纬度所在城市
  10. C语言中字符串
  11. css 设置 checkbox复选框控件的对勾√样式
  12. 随心测试_软测基础_002_&lt;测试工程师_核心技能体系&gt;
  13. Go语言生成随机数
  14. MySQL服务器监控注意事项
  15. centos下安装必要组件(相当于apt-get install install build-essential)
  16. Javascript Madness: Mouse Events
  17. sql日期查询
  18. Java: Replace a string from multiple replaced strings to multiple substitutes
  19. Mysql Fabric实现学习笔记
  20. DataTable To Entity

热门文章

  1. ASP.NET Core端点路由 作用原理
  2. 有效提高java编程安全性的12条黄金法则
  3. 我和ABP vNext 的故事
  4. ant design pro 实战 : 使用 ztree
  5. Java中Map的entrySet()详解
  6. TeamViewer如何绑定谷歌二次验证码/谷歌身份验证?
  7. 常用CSS颜色表
  8. 深入探究JVM之垃圾回收器
  9. scrapyd 部署
  10. 详解 MySQL 面试核心知识点