建造者模式(Builder Pattern)也叫做生成器模式,是 GoF 的 23 种设计模式的一种,它将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。 当我们需要实列化一个复杂的类,以得到不同结构类型和不同的内部状态的对象时,我们可以用不同的类对它们的实列化操作逻辑分别进行封装,这些类我们就称之为建造者。 ~ 本篇内容包括:关于建造者模式、建造者模式 Demo、使用建造者模式进行重构
文章目录- 一、关于建造者模式
- 1、关于建造者模式
- 2、关于建造者模式的构成
- 3、关于建造者模式的优缺点
- 4、关于建造者模式与工厂模式区别
- 1、关于建造者模式
- 2、关于建造者模式的构成
- 3、关于建造者模式的优缺点
- 4、关于建造者模式与工厂模式区别
- 二、建造者模式 Demo
- 1、Demo 设计
- 2、Demo 实现
- 3、Demo 测试
- 三、使用建造者模式进行重构
- 1、重构前代码
- 2、重构前使用
- 3、重构后代码
- 4、重构后使用
一、关于建造者模式
1、关于建造者模式
建造者模式(Builder Pattern)也叫做生成器模式,是 GoF 的 23 种设计模式的一种,它将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
当我们需要实列化一个复杂的类,以得到不同结构类型和不同的内部状态的对象时,我们可以用不同的类对它们的实列化操作逻辑分别进行封装,这些类我们就称之为建造者。
当我们需要来自同一个类,但是要就有不同结构对象时,就可以通过构造另一个建造者来进行实列化。
建造者(Builder)模式创建的是复杂对象,其产品的各个部分经常面临着剧烈的变化,但将它们组合在一起的算法却相对稳定,所以它通常在以下场合使用。
- 创建的对象较复杂,由多个部件构成,各部件面临着复杂的变化,但构件间的建造顺序是稳定的。
- 创建复杂对象的算法独立于该对象的组成部分以及它们的装配方式,即产品的构建过程和最终的表示是独立的。
2、关于建造者模式的构成
建造者模式包含如下角色:
- 抽象建造者类(Builder):这个接口规定要实现包含创建产品各个子部件的抽象方法以及返回复杂产品的方法,并不涉及具体的部件对象的创建。
- 具体建造者类(ConcreteBuilder):实现抽象 Builder 定义的所有方法,并且返回一个装配好的对象。
- 产品类(Product):一般是多个部件组成的复杂对象,由具体建造者来创建其各个零部件。
- 指挥者类(Director):负责安排已有模块的顺序,然后调用 Builder 建造产品。
3、关于建造者模式的优缺点
# 优点
- 封装性,在建造者模式中,调用方不必知道产品内部组成的细节,将一个复杂对象的构建与它的表示分离,使得相同的创建过程可以创建不同的产品对象。
- 扩展性,每个具体建造者都相互独立,替换具体建造者或新增具体建造者都很便捷。
- 更关注 “由零件一步一步地组装出产品对象”。将复杂产品的创建步骤拆分到不同的方法中,使得创建过程更加清晰。
# 缺点
- 建造者模式所创建的产品对象一般组成部分相似,如果产品的内部变化复杂,需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大。
- 如果产品内部结构发生变化,建造者也要相应修改,有较大的维护成本。
4、关于建造者模式与工厂模式区别
- 工厂模式,一般都是创建一个产品,注重的是把这个产品创建出来就行,只要创建出来,不关心这个产品的组成部分。从代码上看,工厂模式就是一个方法,用这个方法就能生产出产品。,,
- 建造者模式,也是创建一个产品,但是不仅要把这个产品创建出来,还要关系这个产品的组成细节,组成过程。 从代码上看,建造者模式在建造产品时,这个产品有很多方法,建造者模式会根据这些相同方法但是不同执行顺序建造出不同组成细节的产品。
二、建造者模式 Demo
1、Demo 设计
生产汽车是一个复杂的过程,它包含了车架,车座等等组件的生产,而车架又有碳纤维,铝合金等材质的,车座有橡胶,真皮等材质。对于汽车的生产就可以使用建造者模式。
2、Demo 实现
# Car 产品类
代码语言:javascript复制public class Car {
/**
* 车架
*/
private String frame;
/**
* 座椅
*/
private String seat;
public String getFrame() {
return frame;
}
public void setFrame(String frame) {
this.frame = frame;
}
public String getSeat() {
return seat;
}
public void setSeat(String seat) {
this.seat = seat;
}
}
# Builder 抽象建造者类
代码语言:javascript复制public abstract class Builder {
protected Car car = new Car();
/**
* 建造车架
*/
public abstract void buildFrame();
/**
* 建造座椅
*/
public abstract void buildSeat();
/**
* 造车
*
* @return Car
*/
public abstract Car createCar();
}
# ACarBulider 具体建造者类
代码语言:javascript复制public class ACarBuilder extends Builder {
@Override
public void buildFrame() {
car.setFrame("铝合金车架");
}
@Override
public void buildSeat() {
car.setSeat("真皮车座");
}
@Override
public Car createCar() {
return car;
}
}
# BCarBulider 具体建造者类
代码语言:javascript复制public class BCarBuilder extends Builder {
@Override
public void buildFrame() {
car.setFrame("碳纤维车架");
}
@Override
public void buildSeat() {
car.setSeat("皮革车座");
}
@Override
public Car createCar() {
return car;
}
}
# Director 指挥者类
代码语言:javascript复制public class Director {
private final Builder mBuilder;
public Director(Builder builder) {
mBuilder = builder;
}
public Car construct() {
mBuilder.buildFrame();
mBuilder.buildSeat();
return mBuilder.createCar();
}
}
3、Demo 测试
代码语言:javascript复制public class Client {
private static void showCar(Builder builder) {
Director director = new Director(builder);
Car car = director.construct();
System.out.println(car.getFrame());
System.out.println(car.getSeat());
}
public static void main(String[] args) {
showCar(new ACarBuilder());
showCar(new BCarBuilder());
}
}
三、使用建造者模式进行重构
建造者模式除了上面的用途外,在开发中还有一个常用的使用方式,就是当一个类构造器需要传入很多参数时,如果创建这个类的实例,代码可读性会非常差,而且很容易引入错误,此时就可以利用建造者模式进行重构。
1、重构前代码
代码语言:javascript复制public class Phone {
private String cpu;
private String screen;
private String memory;
private String mainboard;
public Phone(String cpu, String screen, String memory, String mainboard) {
this.cpu = cpu;
this.screen = screen;
this.memory = memory;
this.mainboard = mainboard;
}
public String getCpu() {
return cpu;
}
public void setCpu(String cpu) {
this.cpu = cpu;
}
public String getScreen() {
return screen;
}
public void setScreen(String screen) {
this.screen = screen;
}
public String getMemory() {
return memory;
}
public void setMemory(String memory) {
this.memory = memory;
}
public String getMainboard() {
return mainboard;
}
public void setMainboard(String mainboard) {
this.mainboard = mainboard;
}
@Override
public String toString() {
return "Phone{"
"cpu='" cpu '''
", screen='" screen '''
", memory='" memory '''
", mainboard='" mainboard '''
'}';
}
}
2、重构前使用
代码语言:javascript复制public class Client {
public static void main(String[] args) {
//构建Phone对象
Phone phone = new Phone("intel", "三星屏幕", "金士顿", "华硕");
System.out.println(phone);
}
}
3、重构后代码
代码语言:javascript复制public class Phone {
private String cpu;
private String screen;
private String memory;
private String mainboard;
private Phone(Builder builder) {
cpu = builder.cpu;
screen = builder.screen;
memory = builder.memory;
mainboard = builder.mainboard;
}
public static final class Builder {
private String cpu;
private String screen;
private String memory;
private String mainboard;
public Builder() {
}
public Builder cpu(String val) {
cpu = val;
return this;
}
public Builder screen(String val) {
screen = val;
return this;
}
public Builder memory(String val) {
memory = val;
return this;
}
public Builder mainboard(String val) {
mainboard = val;
return this;
}
public Phone build() {
return new Phone(this);
}
}
@Override
public String toString() {
return "Phone{"
"cpu='" cpu '''
", screen='" screen '''
", memory='" memory '''
", mainboard='" mainboard '''
'}';
}
}
4、重构后使用
代码语言:javascript复制public class Client {
public static void main(String[] args) {
Phone phone = new Phone.Builder()
.cpu("intel")
.mainboard("华硕")
.memory("金士顿")
.screen("三星")
.build();
System.out.println(phone);
}
}