设计模式之美
王争
前 Google 工程师,《数据结构与算法之美》专栏作者
123425 人已学习
新⼈⾸单¥98
登录后,你可以任选6讲全文学习
课程目录
已完结/共 113 讲
设计模式与范式:行为型 (18讲)
设计模式之美
15
15
1.0x
00:00/00:00
登录|注册

46 | 建造者模式:详解构造函数、set方法、建造者模式三种对象创建方式

通过设置不同的可选参数来定制化创建不同的对象
用于创建一种类型的复杂对象
由给定的参数决定创建哪种类型的对象
用于创建不同但相关类型的对象
创建不可变对象
将校验逻辑放置到Builder类中
创建不可变对象的需求
属性之间的依赖关系或约束条件无法校验
set方法无法校验必填项
构造函数参数过多导致可读性差
完善ConstructorArg类
与工厂模式的区别
应用场景和避免过度使用
建造者模式的原理和实现
建造者模式
工厂模式
建造者模式的解决方案
构造函数和set方法的局限性
课堂讨论
重点回顾
与工厂模式有何区别?
为什么需要建造者模式?
详解构造函数、set方法、建造者模式三种对象创建方式

该思维导图由 AI 生成,仅供参考

上两节课中,我们学习了工厂模式,讲了工厂模式的应用场景,并带你实现了一个简单的 DI 容器。今天,我们再来学习另外一个比较常用的创建型设计模式,Builder 模式,中文翻译为建造者模式或者构建者模式,也有人叫它生成器模式
实际上,建造者模式的原理和代码实现非常简单,掌握起来并不难,难点在于应用场景。比如,你有没有考虑过这样几个问题:直接使用构造函数或者配合 set 方法就能创建对象,为什么还需要建造者模式来创建呢?建造者模式和工厂模式都可以创建对象,那它们两个的区别在哪里呢?
话不多说,带着上面两个问题,让我们开始今天的学习吧!

为什么需要建造者模式?

在平时的开发中,创建一个对象最常用的方式是,使用 new 关键字调用类的构造函数来完成。我的问题是,什么情况下这种方式就不适用了,就需要采用建造者模式来创建对象呢?你可以先思考一下,下面我通过一个例子来带你看一下。
假设有这样一道设计面试题:我们需要定义一个资源池配置类 ResourcePoolConfig。这里的资源池,你可以简单理解为线程池、连接池、对象池等。在这个资源池配置类中,有以下几个成员变量,也就是可配置项。现在,请你编写代码实现这个 ResourcePoolConfig 类。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文深入探讨了构造函数、set方法和建造者模式三种对象创建方式,并阐述了它们的优劣势及适用场景。通过资源池配置类的例子引出了建造者模式的应用场景,分析了构造函数和set方法可能存在的问题,并指出了建造者模式的优势,如避免无效状态、集中校验逻辑、创建不可变对象等。文章还对比了工厂模式和建造者模式的区别,强调了理解模式设计的本质和灵活应用的重要性。总之,本文内容简洁明了,对于读者快速了解建造者模式的概念和使用具有很高的参考价值。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《设计模式之美》
新⼈⾸单¥98
立即购买
登录 后留言

全部留言(148)

  • 最新
  • 精选
  • zhengyu.nie
    依赖关系(Dependencies)、合法校验(Preconditions)、不可变(Immutable)。 争哥这几个描述很精准! 借着思路延伸一下的话,很多库和设计都是以上这些理念的。 比如com.google.guava的校验、不可变集合,多线程设计模式中的Immutable模式、保护性拷贝(其中又可以分深浅api),java.lang.String的不可变设计。还有关于类状态的控制,还有Effective Java中类创建这一章中对于构造方法、set方法、Builder构建、枚举、静态工厂方法构建等对比,像Guava Lists、Sets、Maps、ImmutableList这种创建方式现在也很主流了

    作者回复: 👍

    2020-04-28
    2
    44
  • 苏暮沉觞
    小争哥,我在学习建造者模式的时候,发现传统的构建者模式写法跟文中的不太一样,传统的构建者模式存在监工,抽象Builder,具体Builder,产品类。可以通过不同的具体Builder,创建对应的产品类。而你在文章中的设计模式的写法,在某些文章中,被称为变种的构造者模式。 我比较了一下两种方式,感觉传统的构建者模式需要提前定义好你要生产的产品对应的属性,而文中这种方法则是在构建产品时,自己动态的设置产品属性,虽然说这种方法更加灵活,但是侵入性更高。 那么考虑到以后需求变更,是不是应该是用传统的构建者模式呢?不然要是资源池对应的参数变了,就要修改业务代码中的参数了。

    作者回复: 在真实的项目里,大部分都是用我说的这种实现方式吧。你说的监工、抽象builder、具体builder的实现方式,有具体的例子吗?

    2020-05-21
    4
  • 悠南
    你这建造者模式代码,看不懂,构造方法私有了,怎么来的Builder 方法

    作者回复: 内部类可以直接调用外部类的成员和方法,包括private的吧

    2020-06-22
    3
    1
  • 是非~成败~
    /** * 需求: * 当 isRef 为 true 的时候,arg 表示 String 类型的 refBeanId,type 不需要设置; * 当 isRef 为 false 的时候,arg、type 都需要设置。 * 请根据这个需求,完善 ConstructorArg 类。 */ public class ConstructorArg_02 { private boolean isRef; private Class type; private Object arg; private ConstructorArg_02(Builder builder) { this.isRef = builder.isRef; this.type = builder.type; this.arg = builder.arg; } public static class Builder { private boolean isRef; private Class type; private Object arg; // 后面两个参数依赖isRef,所以isRef设置成必选参数 public Builder(boolean isRef) { this.isRef = isRef; } public ConstructorArg_02 build() { return new ConstructorArg_02(this); } public Builder setType(Class type) { this.type = type; return this; } public Builder setArg(Object arg) { // isRef为true, arg不是String类型就报错 if (isRef && arg.getClass() != String.class) { throw new RuntimeException("参数错误"); } this.arg = arg; return this; } } } 咱也不知道写的好不好,希望争哥看到了检视指导一二

    作者回复: 不错!

    2020-11-16
  • Morse
    为什么定义了一个长方形类,如果不使用建造者模式,采用先创建后 set 的方式,那就会导致在第一个 set 之后,对象处于无效状态?求大佬解答

    作者回复: 那就要用builder模式了

    2020-08-03
    5
  • Darren
    简单理解就是:工厂模式是根据不同的条件生成不同Class的对象,构建者模式是根据不同参数生成一个class的不同对象。
    2020-04-10
    4
    126
  • webmin
    public class ConstructorArg { private boolean isRef; private Class type; private Object arg; public boolean isRef() { return isRef; } public Class getType() { return type; } public Object getArg() { return arg; } private ConstructorArg(Builder builder) { this.isRef = builder.isRef; this.type = builder.type; this.arg = builder.arg; } public static class Builder { private boolean isRef; private Class type; private Object arg; public ConstructorArg build() { if(isRef && type != null) { throw new IllegalArgumentException("..."); } if (!isRef && type == null) { throw new IllegalArgumentException("..."); } if (this.isRef && (arg != null && arg.getClass() != String.class)) { throw new IllegalArgumentException("..."); } if (!this.isRef && arg == null) { throw new IllegalArgumentException("..."); } return new ConstructorArg(this); } public Builder setRef(boolean ref) { if(ref && this.type != null) { throw new IllegalArgumentException("..."); } this.isRef = ref; return this; } public Builder setType(Class type) { if (this.isRef || type == null) { throw new IllegalArgumentException("..."); } this.type = type; return this; } public Builder setArg(Object arg) { if (this.isRef && (arg != null && arg.getClass() != String.class)) { throw new IllegalArgumentException("..."); } if (!this.isRef && arg == null) { throw new IllegalArgumentException("..."); } this.arg = arg; return this; } } }
    2020-02-17
    13
    114
  • 相逢是缘
    打卡 一、使用场景: 1)类的构造函数必填属性很多,通过set设置,没有办法校验必填属性 2)如果类的属性之间有一定的依赖关系,构造函数配合set方式,无法进行依赖关系和约束条件校验 3)需要创建不可变对象,不能暴露set方法。 (前提是需要传递很多的属性,如果属性很少,可以不需要建造者模式) 二、实现方式: 把构造函数定义为private,定义public static class Builder 内部类,通过Builder 类的set方法设置属性,调用build方法创建对象。 三、和工厂模式的区别: 1)工厂模式:创建不同的同一类型对象(集成同一个父类或是接口的一组子类),由给定的参数来创建哪种类型的对象; 2)建造者模式:创建一种类型的复杂对象,通过很多可设置参数,“定制化”的创建对象
    2020-02-17
    4
    55
  • javaadu
    课堂讨论题: /** * 在下面的 ConstructorArg 类中, * 当 isRef 为 true 的时候,arg 表示 String 类型的 refBeanId,type 不需要设置; * 当 isRef 为 false 的时候,arg、type 都需要设置 * * @author javaadu */ public class ConstructorArg { private boolean isRef; private Class type; private Object arg; private ConstructorArg(Builder builder) { this.isRef = builder.isRef; this.type = builder.type; this.arg = builder.arg; } public static class Builder { private boolean isRef; private Class type; private Object arg; public ConstructorArg build() { if (arg == null) { throw new IllegalArgumentException("arg必须设置"); } if (isRef) { if (!(arg instanceof String)) { throw new IllegalArgumentException("arg必须为String类型的对象"); } } else { if (type == null) { throw new IllegalArgumentException("arg必须设置"); } } return new ConstructorArg(this) } public Builder setRef(boolean ref) { isRef = ref; return this; } public Builder setArg(Object arg) { this.arg = arg; return this; } public Builder setType(Class type) { this.type = type; return this; } } }
    2020-02-17
    51
  • 小文同学
    说说自己读了 Builder 模式的最大感悟: 1、Builder 模式可以保证对象的状态。 2、Builder 模式可以把对象的构造鉴定逻辑写在Builder类中,保证了类的简洁。 平时普普通通地使用 lombok 生成 Builder,应该更加深入地了解一下。
    2020-03-07
    17
收起评论
显示
设置
留言
99+
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部