定义
将一个复制对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示,用户只需指定需要建造的类型就可以得到他们,建造过程及细节不需要知道。
使用场景
- 如果一个对象有非常复杂的内部结构(很多属性)
- 想把复杂对象的创建和使用分离
当一个类的构造函数参数个数超过4个,而且这些参数有些是可选的参数,考虑使用构造者模式。
建造者与工厂模式区别
建造者模式:
- 更注重于方法的调用顺序
- 粒度:创建复杂的产品,由各种复杂的部件组成 工厂模式:
- 注重于创建产品
-
UML
角色结构
Product: 最终要生成的对象。
- Builder: 构建者的抽象基类(有时会使用接口代替)。其定义了构建Product的抽象步骤,其实体类需要实现这些步骤。其会包含一个用来返回最终产品的方法
Product getProduct()
。 - ConcreteBuilder: Builder的实现类。
Director: 决定如何构建最终产品的算法. 其会包含一个负责组装的方法
void Construct(Builder builder)
, 在这个方法中通过调用builder的方法,就可以设置builder,等设置完成后,就可以通过builder的getProduct()
方法获得最终的产品。优点
建造者独立,易扩展。
便于控制细节风险。 :::info 另外适用于快速失败,在 build 时可以做校验,如果不满足必要条件,则可以直接抛出创建异常,在 OkHttp3 中的 Request.Builder 中就是这样用的。
public Request build() {
if (url == null) throw new IllegalStateException(“url == null”);
return new Request(this);
} :::缺点
产品必须有共同点,范围有限制。
-
代码示例
Computer.java 目标Computer类
@Setter
@ToString
public class Computer {
/**
* 必须
*/
private String cpu;
/**
* 必须
*/
private String ram;
/**
* 可选
*/
private int usbCount;
/**
* 可选
*/
private String keyboard;
/**
* 可选
*/
private String display;
public Computer(String cpu, String ram) {
this.cpu = cpu;
this.ram = ram;
}
}
ComputerBuilder.java 抽象构建者类
public abstract class ComputerBuilder {
public abstract void setUsbCount();
public abstract void setKeyboard();
public abstract void setDisplay();
public abstract Computer getComputer();
}
MacComputerBuilder.java 实体构建者类
```java public class MacComputerBuilder extends ComputerBuilder {
private Computer computer;
public MacComputerBuilder(String cpu, String ram) {
computer = new Computer(cpu, ram);
} @Override public void setUsbCount() {
computer.setUsbCount(2);
} @Override public void setKeyboard() {
computer.setKeyboard("苹果键盘");
} @Override public void setDisplay() {
computer.setDisplay("苹果显示器");
} @Override public Computer getComputer() {
return computer;
}
<a name="hJf3S"></a>
#### LenovoComputerBuilder.java 联想电脑构建者类
```java
public class LenovoComputerBuilder extends ComputerBuilder {
private Computer computer;
public LenovoComputerBuilder(String cpu, String ram) {
computer = new Computer(cpu, ram);
}
@Override
public void setUsbCount() {
computer.setUsbCount(4);
}
@Override
public void setKeyboard() {
computer.setKeyboard("联想键盘");
}
@Override
public void setDisplay() {
computer.setDisplay("联想显示器");
}
@Override
public Computer getComputer() {
return computer;
}
}
ComputerDirector.java 指导者类(Director)
public class ComputerDirector {
public void makeComputer(ComputerBuilder builder){
builder.setUsbCount();
builder.setDisplay();
builder.setKeyboard();
}
}
Client.java
public class Client {
public static void main(String[] args) {
//1
ComputerDirector director=new ComputerDirector();
//2
ComputerBuilder builder=new MacComputerBuilder("I5处理器","三星125");
//3
director.makeComputer(builder);
//4
Computer macComputer=builder.getComputer();
System.out.println("mac computer:"+macComputer.toString());
ComputerBuilder lenovoBuilder=new LenovoComputerBuilder("I7处理器","海力士222");
director.makeComputer(lenovoBuilder);
Computer lenovoComputer=lenovoBuilder.getComputer();
System.out.println("lenovo computer:"+lenovoComputer.toString());
}
}
输出
mac computer:Computer(cpu=I5处理器, ram=三星125, usbCount=2, keyboard=苹果键盘, display=苹果显示器)
lenovo computer:Computer(cpu=I7处理器, ram=海力士222, usbCount=4, keyboard=联想键盘, display=联想显示器)
构造者模式的变种
首先其省略了director 这个角色,将构建算法交给了client端,其次将builder 写到了要构建的产品类里面,最后采用了链式调用。
如何实现
- 在Computer 中创建一个静态内部类 Builder,然后将Computer 中的参数都复制到Builder类中。
- 在Computer中创建一个private的构造函数,参数为Builder类型
- 在Builder中创建一个
public
的构造函数,参数为Computer中必填的那些参数,cpu 和ram。 - 在Builder中创建设置函数,对Computer中那些可选参数进行赋值,返回值为Builder类型的实例
在Builder中创建一个
build()
方法,在其中构建Computer的实例并返回代码示例
Computer.java
@ToString
public class Computer {
/**
* 必须
*/
private String cpu;
/**
* 必须
*/
private String ram;
/**
* 可选
*/
private int usbCount;
/**
* 可选
*/
private String keyboard;
/**
* 可选
*/
private String display;
private Computer(Builder builder){
this.cpu=builder.cpu;
this.ram=builder.ram;
this.usbCount=builder.usbCount;
this.keyboard=builder.keyboard;
this.display=builder.display;
}
public static class Builder{
private String cpu;//必须
private String ram;//必须
private int usbCount;//可选
private String keyboard;//可选
private String display;//可选
public Builder(String cup,String ram){
this.cpu=cup;
this.ram=ram;
}
public Builder setUsbCount(int usbCount) {
this.usbCount = usbCount;
return this;
}
public Builder setKeyboard(String keyboard) {
this.keyboard = keyboard;
return this;
}
public Builder setDisplay(String display) {
this.display = display;
return this;
}
public Computer build(){
return new Computer(this);
}
}
}
Client.java
public class Client {
public static void main(String[] args) {
Computer computer = new Computer.Builder("因特尔", "三星")
.setDisplay("三星24寸")
.setKeyboard("罗技")
.setUsbCount(2)
.build();
System.out.println(computer.toString());
}
}
输出
Computer(cpu=因特尔, ram=三星, usbCount=2, keyboard=罗技, display=三星24寸)
框架示例