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. web 部署专题(八):Nginx 反向代理中cookie相关问题

    问题3:认证问题 Domino服务器中,通过写了一些接口代码,提供RESTful的服务,来对手机端进行提供服务.但是由于原来的环境,没有SSO,而且不通过认证,没法访问到Domino里面的接口代码. ...

  2. HangFire多集群切换及DashBoard登录验证

    项目中是有多个集群的,现在存在一个是:在切换web集群时,如何切换HangFire的周期性任务. 先采取的解决办法是: 每个集群分一个队列,在周期性任务入队时分配当前web集群的集群id单做队列名称. ...

  3. 初识Java对象

    初始Java对象 本文的概述顺序 1什么是面向对象编程(面向对象编程与 面向过程编程的区别) 2类和对象的的关系 3类的定义 4对象的创建 5对象使用的一些细节 5.1对象在内存中的产生及分布 5.2 ...

  4. 普通list和树状list互转

    import java.util.ArrayList; import java.util.List; public class TreeNode { private String id; privat ...

  5. Ethical Hacking - NETWORK PENETRATION TESTING(9)

    WEP Cracking Packet Injection What if the AP was idle, or had no clients associated with it? In this ...

  6. HTTP请求方式及常见问题

    请求方式 当前HTTP一共有八种方式.有三种是有HTTP1.0提供,剩余五种则是有HTTP1.1提供 常见问题 啥是OPTIONS?有啥作用 是浏览器对复杂跨域请求的一种处理方式,在真正发送请求之前, ...

  7. Java 中的链式编程

    前言 ​ 在写项目的时候,有一个实体类有好多个属性,new 出来之后需要不停的使用setXXX( )方法,效率低而且代码可读性差,查询了下发现可以实现实体类的链式编程. public class Us ...

  8. .Net Core AES加解密

    项目中token在传输过程中采用了AES加密,  网上找到的两篇博文都有写问题,在这里记录一下.Net Core 2.2代码中AES加解密的使用: //AES加密 传入,要加密的串和, 解密key p ...

  9. Flutter获取远程数据 刷新UI界面

    import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; void main() => r ...

  10. lua中 string.find(查找获取字符串) string.gsub(查找替换字符串) string.sub(截取字符串)

    > aaa='/p/v2/api/winapi/adapter/lgj'> print(string.find(aaa, "^/.+/adapter/(.*)"))1 ...