发布于: 2022-10-30最后更新: 2022-10-30字数 1373阅读时长 4 分钟

type
Post
status
Published
date
Oct 30, 2022
slug
builder-design-pattern-of-creation-pattern
summary
tags
建造者
category
设计模式
icon
password
 

一、为什么需要建造者模式

 
有这么一个场景,有一个资源池配置类 ResourcePoolConfig,有许多需要配置的成员变量,有的需要必填,有的不需要,有的有默认值等等,简单的实现是:
  • 直接通过构造函数中添加所有的成员变量进行赋值,非必填可以传递空值即可
  • 同时在构造函数中进行所有参数的合法性判断即可
 
更加复杂的场景下,参数或者说成员变量有很多都通过构造函数进行赋值,可能会乱,顺序出错等等问题,同时参数合法性判断也会导致构造函数臃肿,不利于维护,因此需要有一种更好的方式来处理这种情况:即可以分离必填和非必填项:
  • 构造器函数参数只设置必填的成员变量
  • 非必填项都通过 set 方法进行设置
 
但是在一些场景下,通过简单的 set 也没办法解决问题:
  • 必填参数很多,都放到构造函数中则又会出现了上面的顺序错乱易出错的问题
  • 若参数有依赖关系,例如这个参数必须大于另一个参数的值,此时 set 方法中无法解决,因为必须得等所有参数都有值了才能进行校验
  • 如果我们希望 ResourcePoolConfig 类对象是不可变对象,也就是说,对象在创建好之后,就不能再修改内部的属性值。要实现这个功能,就不能在 ResourcePoolConfig 类中暴露 set() 方法。
 
为了解决上面的问题,一个好的解决方案就是使用建造者模式
  1. 先创建建造者,并通过 set() 方法设置建造者的变量值
  1. 在使用 build() 方法真正创建对象之前,做集中的校验,校验通过之后才会创建对象
  1. 可以把 ResourcePoolConfig 的构造函数改为 private 私有权限,这样我们就只能通过建造者来创建 ResourcePoolConfig 类对象。
  1. ResourcePoolConfig 没有提供任何 set() 方法,这样我们创建出来的对象就是不可变对象了
 
使用建造者模式创建对象,还能避免对象存在无效状态。
如我们定义了一个长方形类,如果不使用建造者模式,采用先创建后 set 的方式,那就会导致在第一个 set 之后,对象处于无效状态(即长方形不能只有长或宽)。
可以使用构造函数传入两个参数解决,同样若必填参数过多同样会有问题,因此使用建造者模式就比较合理了。先设置建造者的变量,然后再一次性地创建对象,让对象一直处于有效状态。
 
建造者模式的一个问题:
使用建造者模式来构建对象,代码实际上是有点重复的,ResourcePoolConfig 类中的成员变量,要在 Builder 类中重新再定义一遍!
 

二、与工厂模式有什么区别

 
网上有一个经典的例子很好地解释了两者的区别:
顾客走进一家餐馆点餐,我们利用工厂模式,根据用户不同的选择,来制作不同的食物,比如披萨、汉堡、沙拉。对于披萨来说,用户又有各种配料可以定制,比如奶酪、西红柿、起司,我们通过建造者模式根据用户选择的不同配料来制作披萨。
  • 工厂模式是用来创建不同但是相关类型的对象(继承同一父类或者接口的一组子类),由给定的参数来决定创建哪种类型的对象
  • 建造者模式是用来创建一种类型的复杂对象,通过设置不同的可选参数,“定制化”地创建不同的对象
 

Loading...
创建型模式之原型设计模式

创建型模式之原型设计模式


创建型模式之工厂设计模式

创建型模式之工厂设计模式