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

发哥讲

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

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

8、Builder 建造者模式 组装复杂的实例 创造型模式的更多相关文章

  1. 7、Prototype 原型模式 通过复制创造实例 创造型模式

    2020-07-19 发哥讲 发哥讲 其实上一节的末尾讲到如何去生成对象,其中有一个关于clone的,这其实就是Prototype原型模式. 通过克隆(拷贝)的方式生成对象 1.了解Prototype ...

  2. [WCF编程]7.实例上下文模式

    一.实例上下文模式概述 实例上下文(IntanceContext Mode)表示服务端的服务实例与客户端的服务代理的绑定方式. 在实例化服务器对象时,WCF采用了3种不同的模式:单调(Per-Call ...

  3. 一天一个设计模式——Builder建造者模式

    一.模式说明 在现实世界中,当我们要构造一个大型工程时(建一个大楼),通常的做法是先建造工程的每个独立部分,然后再逐步构造完成(先打地基,再搭框架,最后逐层累造).在程序设计领域,构造一个复杂的类时( ...

  4. Android设计模式——Builder(建造者)模式

    1.建造者模式是一步一步创建一个复杂对象的创建模式.该模式是为了将构建复杂对象的过程和他的部件解耦,使得构建过程和部件表示隔离开. 2.Bulider模式的定义是:将一个复杂对象的构建与它的表示分离, ...

  5. WCF实例上下文模式与并发模式对性能的影响

    实例上下文模式 InstanceContextMode 控制在响应客户端调用时,如何分配服务实例.InstanceContextMode 可以设置为以下值: •Single – 为所有客户端调用分配一 ...

  6. MVC实例应用模式

    MVC实例应用模式 1.可用性: 比如异常处理 2.可修改性: 比如用接口实现 3.性能战术: 4.易用性战术: 分层实现 5.可测试性战术: 实现对其接口进行测试,并不需要对其实现方法进行 6.安全 ...

  7. MVC(Model -View-Controller)实例应用模式

    MVC(Model -View-Controller)实例应用模式 以登录为例: Model:User package com.keith.bean; public class TUser imple ...

  8. WCF - 服务实例管理模式

    WCF 提供了三种实例上下文模式:PreCall.PreSession 以及 Single.开发人员通过 ServiceBehavior.InstanceContextMode 就可以很容易地控制服务 ...

  9. 抽象工厂模式(Abstract Factory)C#实例

    抽象工厂模式(Abstract Factory)C#实例 本文出处http://www.dofactory.com/net/abstract-factory-design-pattern 一.场景描述 ...

随机推荐

  1. 机器学习实战基础(十五):sklearn中的数据预处理和特征工程(八)特征选择 之 Filter过滤法(二) 相关性过滤

    相关性过滤 方差挑选完毕之后,我们就要考虑下一个问题:相关性了. 我们希望选出与标签相关且有意义的特征,因为这样的特征能够为我们提供大量信息.如果特征与标签无关,那只会白白浪费我们的计算内存,可能还会 ...

  2. 机器学习实战基础(九):sklearn中的数据预处理和特征工程(二) 数据预处理 Preprocessing & Impute 之 数据无量纲化

    1 数据无量纲化 在机器学习算法实践中,我们往往有着将不同规格的数据转换到同一规格,或不同分布的数据转换到某个特定分布的需求,这种需求统称为将数据“无量纲化”.譬如梯度和矩阵为核心的算法中,譬如逻辑回 ...

  3. scrapy 源码解析 (二):启动流程源码分析(二) CrawlerProcess主进程

    CrawlerProcess主进程 它控制了twisted的reactor,也就是整个事件循环.它负责配置reactor并启动事件循环,最后在所有爬取结束后停止reactor.另外还控制了一些信号操作 ...

  4. one-hot 编码

    def onehot(labels): '''one-hot 编码''' #数据有几行输出 n_sample = len(labels) #数据分为几类.因为编码从0开始所以要加1 n_class = ...

  5. 大牛聊Java并发编程原理之 线程的互斥与协作机制

    可能在synchronized关键字的实现原理中,你已经知道了它的底层是使用Monitor的相关指令来实现的,但是还不清楚Monitor的具体细节.本文将让你彻底Monitor的底层实现原理. 管程 ...

  6. stm32-HAL库串口收发

    串口发送 重写fputc函数 /* 优点 直接使用printf函数,发送数据长度无限制,不需要额外的数组空间 缺点 只能对应一个串口,暂时没想到解决方案 */ //头文件中要包含 stdio.h 然后 ...

  7. ubuntu 12.04无盘工作站

    注释:该篇博文是借鉴下列文章加上自己实践总结得来: a. http://forum.ubuntu.org.cn/viewtopic.php?f=77&t=117754 b. http://bl ...

  8. mysql字符集 utf8 和utf8mb4 的区别

    一.导读我们新建mysql数据库的时候,需要指定数据库的字符集,一般我们都是选择utf8这个字符集,但是还会又一个utf8mb4这个字符集,好像和utf8有联系,今天就来解析一下这两者的区别. 二.起 ...

  9. ES数据库搜索

    1.倒排索引 1.倒排索引和正向索引 在全文搜索里,文档数据离不开搜索,而搜索离不开索引(没有索引搜索会很低效),倒排索引(Inverted index)是全文搜索系统里最高效的索引方法和数据结构,E ...

  10. 在excel中如何给一列数据批量加上双引号

    在实际开发中,会遇到这样的需求,大量的数据,需要从配置文件里读取,客户给到的枚举值是字符串,而配置文件里的数据,是json格式,需要加上双引号,这样就需要使用Excel来批量格式化一下数据. 客户给到 ...