定义
将一个复制对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示,用户只需指定需要建造的类型就可以得到他们,建造过程及细节不需要知道。
使用场景
- 如果一个对象有非常复杂的内部结构(很多属性)
- 想把复杂对象的创建和使用分离
当一个类的构造函数参数个数超过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@ToStringpublic 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 联想电脑构建者类```javapublic class LenovoComputerBuilder extends ComputerBuilder {private Computer computer;public LenovoComputerBuilder(String cpu, String ram) {computer = new Computer(cpu, ram);}@Overridepublic void setUsbCount() {computer.setUsbCount(4);}@Overridepublic void setKeyboard() {computer.setKeyboard("联想键盘");}@Overridepublic void setDisplay() {computer.setDisplay("联想显示器");}@Overridepublic 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) {//1ComputerDirector director=new ComputerDirector();//2ComputerBuilder builder=new MacComputerBuilder("I5处理器","三星125");//3director.makeComputer(builder);//4Computer 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
@ToStringpublic 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寸)
框架示例
