1 简介
建造者模式是设计模式的一种,将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
实用范围
- 当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时。
- 当构造过程必须允许被构造的对象有不同表示时。
角色
在这样的设计模式中,有以下几个角色:
builder
:为创建一个产品对象的各个部件指定抽象接口。ConcreteBuilder
:实现Builder的接口以构造和装配该产品的各个部件,定义并明确它所创建的表示,并提供一个检索产品的接口。Director
:构造一个使用Builder接口的对象。Product
:表示被构造的复杂对象。ConcreteBuilder创建该产品的内部表示并定义它的装配过程,包含定义组成部件的类,包括将这些部件装配成最终产品的接口。
2 应用场景
- 隔离复杂对象的创建和使用,相同的方法,不同执行顺序,产生不同事件结果
- 多个部件都可以装配到一个对象中,但产生的运行结果不相同
- 产品类非常复杂或者产品类因为调用顺序不同而产生不同作用
- 初始化一个对象时,参数过多,或者很多参数具有默认值
- Builder模式不适合创建差异性很大的产品类,产品内部变化复杂,会导致需要定义很多具体建造者类实现变化,增加项目中类的数量,增加系统的理解难度和运行成本
- 需要生成的产品对象有复杂的内部结构,这些产品对象具备共性;
3 代码案例
3.1 案例1
场景:
小明要组装一个电脑,现在有Apple和ASUS两个电脑店,他要选择其中一个去组装一个电脑,电脑的构成无非就是主机、显示器、鼠标和键盘,所以这是组装电脑的一个抽象,两个电脑店是抽象的具体实现,然后电脑店就是一个使用构造接口的对象(可以看做是组装者),最后是Product(组装出来的产品),下面是类关系图:
类关系图:
代码:
Computer.java
/**
* @desc: 电脑实体类
* @author: YanMingXin
* @create: 2021/8/19-15:48
**/
public class Computer {
public String host;
public String screen;
public String mouse;
public String keyBoard;
public Computer(String host, String screen, String mouse, String keyBoard) {
this.host = host;
this.screen = screen;
this.mouse = mouse;
this.keyBoard = keyBoard;
}
public Computer() {
}
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public String getScreen() {
return screen;
}
public void setScreen(String screen) {
this.screen = screen;
}
public String getMouse() {
return mouse;
}
public void setMouse(String mouse) {
this.mouse = mouse;
}
public String getKeyBoard() {
return keyBoard;
}
public void setKeyBoard(String keyBoard) {
this.keyBoard = keyBoard;
}
@Override
public String toString() {
return "Computer{" +
"host='" + host + '\'' +
", screen='" + screen + '\'' +
", mouse='" + mouse + '\'' +
", keyBoard='" + keyBoard + '\'' +
'}';
}
}
Builder.java
/**
* @desc: 抽象建造者
* @author: YanMingXin
* @create: 2021/8/19-16:05
**/
public abstract class Builder {
abstract void buildHost();
abstract void buildScreen();
abstract void buildMouse();
abstract void buildKeyBoard();
abstract Computer createComputer();
}
AppleComputerBuilder.java
/**
* @desc: AppleComputer具体建造者
* @author: YanMingXin
* @create: 2021/8/19-16:09
**/
public class AppleComputerBuilder extends Builder {
private Computer computer = new Computer();
@Override
void buildHost() {
computer.setHost("Apple Host");
}
@Override
void buildScreen() {
computer.setScreen("Apple Screen");
}
@Override
void buildMouse() {
computer.setMouse("Apple Mouse");
}
@Override
void buildKeyBoard() {
computer.setKeyBoard("Apple KeyBoard");
}
@Override
Computer createComputer() {
return computer;
}
}
ASUSComputerBuilder.java
/**
* @desc: ASUSComputer具体建造者
* @author: YanMingXin
* @create: 2021/8/19-16:10
**/
public class ASUSComputerBuilder extends Builder {
private Computer computer = new Computer();
@Override
void buildHost() {
computer.setHost("ASUS Host");
}
@Override
void buildScreen() {
computer.setScreen("ASUS Screen");
}
@Override
void buildMouse() {
computer.setMouse("ASUS Mouse");
}
@Override
void buildKeyBoard() {
computer.setKeyBoard("ASUS KeyBoard");
}
@Override
Computer createComputer() {
return computer;
}
}
Director.java
/**
* @desc: Director角色
* @author: YanMingXin
* @create: 2021/8/19-16:13
**/
public class Director {
private Builder builder;
public Director(Builder builder) {
this.builder = builder;
}
public Computer construct() {
builder.buildHost();
builder.buildKeyBoard();
builder.buildMouse();
builder.buildScreen();
return builder.createComputer();
}
}
MyBuilder.java
/**
* @desc: 建造指挥者
* @author: YanMingXin
* @create: 2021/8/19-14:21
**/
public class MyBuilder {
public static void main(String[] args) {
Director director = new Director(new AppleComputerBuilder());
Computer computer = director.construct();
System.out.println(computer.toString());
}
}
测试结果:
3.2 案例2
场景:
一个实体类有多种属性,但是有的是必要的,有的是不必要的,在某些场景下需要的属性都不尽相同,因此当一个实体类的构造方法大于3个时,我们就要考虑使用建造者模式来改造下实体类,具体的方法就是 将类的构造方法设置参数为Builder,并内置一个静态内部类为Builder,将实体类的属性全部给Builder类,将Builder类的参数全部在实体类的构造方法中赋值给类的属性
下面是具体的演示:
代码:
Car.java
/**
* @desc: 实体类
* @author: YanMingXin
* @create: 2021/8/19-16:22
**/
public class Car {
private String name;
private Double price;
private String tyre;
private String body;
private String windows;
public Car() {
}
public Car(Builder builder) {
this.name = builder.name;
this.price = builder.price;
this.tyre = builder.tyre;
this.body = builder.body;
this.windows = builder.windows;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
public String getTyre() {
return tyre;
}
public void setTyre(String tyre) {
this.tyre = tyre;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
public String getWindows() {
return windows;
}
public void setWindows(String windows) {
this.windows = windows;
}
@Override
public String toString() {
return "Car{" +
"name='" + name + '\'' +
", price=" + price +
", tyre='" + tyre + '\'' +
", body='" + body + '\'' +
", windows='" + windows + '\'' +
'}';
}
/**
* 建造器
*/
static class Builder {
private String name;
private Double price;
private String tyre;
private String body;
private String windows;
public Builder setName(String name) {
this.name = name;
return this;
}
public Builder setPrice(Double price) {
this.price = price;
return this;
}
public Builder setTyre(String tyre) {
this.tyre = tyre;
return this;
}
public Builder setBody(String body) {
this.body = body;
return this;
}
public Builder setWindows(String windows) {
this.windows = windows;
return this;
}
public Car build() {
return new Car(this);
}
}
}
MyBuilder.java
/**
* @desc: 测试类
* @author: YanMingXin
* @create: 2021/8/19-16:21
**/
public class MyBuilder {
public static void main(String[] args) {
Car car = new Car.Builder()
.setBody("s")
.setName("B")
.setPrice(1243.3)
.build();
System.out.println(car);
}
}
测试结果: