一. 简介
以下是百度百科 对建造者模式的解释 : 文章地址
-
解决问题
-
在这样的设计模式中,有以下几个角色:
-
builder:为创建一个产品对象的各个部件指定抽象接口。
-
ConcreteBuilder:实现Builder的接口以构造和装配该产品的各个部件,定义并明确它所创建的表示,并提供一个检索产品的接口。
-
Director:构造一个使用Builder接口的对象。
-
Product:表示被构造的复杂对象。ConcreteBuilder创建该产品的内部表示并定义它的装配过程,包含定义组成部件的类,包括将这些部件装配成最终产品的接口。
-
二. 使用场景分析
以下是我工厂模式文章举的例子:
这个工厂 可以通过指定磁盘和内存 两个参数 去创建一台电脑computer的对象,可是我想在加上一个是否使用喇叭 isSpeaker 的参数 ,有些电脑需要喇叭,有些不需要,所以这个参数不是必须填的了,可是在之前的工厂中,你想创建一台电脑,你就必须要输入指定的参数才可以,可能有很多人说不需要speaker 就输入null就可以了,可是如果这种类似的参数很多呢,要一个个输入null吗?显然是不行的。并且memory和disk是必须输入的参数,这种参数能否和isSpeaker这种可选的参数区分开,方便管理呢?这时候就需要建造者模式去解决这种问题了。
总结上面我个人思考的观点:建造者模式的引入是为了解决工厂和抽象工厂设计模式在对象包含大量属性时的一些问题。当对象包含大量属性时,工厂和抽象工厂设计模式存在三个主要问题。
- 从客户端程序传递到 Factory 类的参数太多,这很容易出错,因为大多数时候,参数的类型是相同的,并且从客户端很难维护参数的顺序。
- 有些参数可能是可选的,但在工厂模式中,我们被迫发送所有参数,并且可选参数需要作为 NULL 发送。
我们可以通过提供带有必需参数的构造函数,然后提供不同的 setter 方法来设置可选参数来解决参数过多的问题。这种方法的问题是,代码可读性会非常差,而且很容易引入错误。 构建器模式通过提供一种 逐步构建对象的方法 来解决这些的问题。
三. 代码案例
当一个类构造器需要传入很多参数时,如果创建这个类的实例,代码可读性会非常差,而且很容易引入错误,比如以下代码,创建一台没有喇叭 的pc电脑,就要在后面输入null,而且这个参数是必须要输入的
Computer pc = ComputerFactory.getComputer("pc", "17 GB", "1 TB",null);
可以通过建造者模式优化以上问题,我设计了如下示意图:
让我们看看如何在 这个案例 中实现建造者设计模式解决问题。
3.1 创建ComputerBuilder 类
/**
* 电脑对象
*
* @author chenyunzhi
* @date 2024/2/25 21:49
*/
public class ComputerBuilder extends Computer{
private final String memory;
private final String disk;
private final Boolean isSpeaker;
/**
* 私有构造函数 以 Builder 类作为参数
*/
private ComputerBuilder(Builder builder) {
this.memory = builder.memory;
this.disk = builder.disk;
this.isSpeaker = builder.isSpeaker;
}
public static class Builder {
private final String memory;
private final String disk;
private Boolean isSpeaker;
public Builder(String memory, String disk) {
this.memory = memory;
this.disk = disk;
}
public Builder setIsSpeaker(Boolean isSpeaker) {
this.isSpeaker = isSpeaker;
return this;
}
/**
* 返回客户端程序所需的对象
*/
public Computer build() {
return new ComputerBuilder(this);
}
}
@Override
public String memory() {
return this.memory;
}
@Override
public String disk() {
return this.disk;
}
@Override
public Boolean isSpeaker() {
return this.isSpeaker;
}
}
代码解析:
-
首先,我们需要创建一个 ComputerBuilder 类 ,里面有Computer 的所有参数,然后在 ComputerBuilder 类 中创建一个 静态嵌套类 Builder ,然后将所有参数从外部类复制到 Builder 类。
-
在 Builder 类中创建一个 公共的 构造函数,并将所有必需的属性作为参数。
-
在Builder 类 中 设置可选参数 isSpeaker 的方法,并且在设置可选属性后应该返回相同的 Builder 对象。
-
最后一步是在 Builder 类中提供一个
build()
方法,该方法将返回客户端程序所需的对象。为此,我们需要在类中有一个私有构造函数,并以 Builder 类作为参数。
3.2 修改子类
public class Laptop extends Computer {
private final String memory;
private final String disk;
private Boolean isSpeaker;
public Laptop(Computer computer) {
this.memory = computer.memory();
this.disk = computer.disk();
this.isSpeaker = computer.isSpeaker();
}
@Override
public String memory() {
return this.memory;
}
@Override
public String disk() {
return this.disk;
}
@Override
public Boolean isSpeaker() {
return this.isSpeaker;
}
}
pc
public class Pc extends Computer {
private final String memory;
private final String disk;
private Boolean isSpeaker;
public Pc(Computer computer) {
this.memory = computer.memory();
this.disk = computer.disk();
this.isSpeaker = computer.isSpeaker();
}
@Override
public String memory() {
return this.memory;
}
@Override
public String disk() {
return this.disk;
}
@Override
public Boolean isSpeaker() {
return this.isSpeaker;
}
}
3.3 修改工厂
ComputerFactory
public static Computer getComputer(String type, Computer computer) {
if (PC.equals(type)) {
return new Laptop(computer);
} else if (LAPTOP.equals(type)) {
return new Pc(computer);
} else {
return null;
}
}
3.4 测试
public class Test
{
public static void main(String[] args) {
Computer laptop = ComputerFactory.getComputer("laptop",
new ComputerBuilder.Builder("17 GB", "1TB").setIsSpeaker(true).build());
Computer pc = ComputerFactory.getComputer("pc",
new ComputerBuilder.Builder("17 GB", "1TB").build());
System.out.println("pc电脑 = " + pc);
System.out.printf("laptop电脑 = " + laptop);
}
}
四. 建造者模式案例
Java 类中的一些构建器模式示例是:
- java.lang.StringBuilder#append()(不同步)
- java.lang.StringBuffer#append() (同步)
这就是 java 中构建器设计模式的全部内容。