继续整理记录这段时间来的收获,详细代码可在我的Gitee仓库SpringBoot克隆下载学习使用!
4.6 建造者模式
4.6.1 概述
- 分离部件构造(由Builder来创建)和装配(Director组装)
- 实现构建与装配解耦
- 用户只需指定复杂对象类型就可得到最终对象,不需关注具体创建细节
4.6.2 结构
- 抽象建造者类(Builder):规定实现复杂对象的创建,不涉及具体创建细节
- 具体建造者类(ConcreteBuilder):实现Builder接口,完成复杂产品的各个部件具体创建方法,且在构造过程完成后提供产品实例
- 产品类(Product):要创建的复杂对象
- 指挥者类(Director):调用具体建造者类创建复杂对象的各个部分,只负责保证对象各部分完整创建或按某种顺序创建
4.6.3 特点
4.6.3.1 优点
- 封装性好,有很好的稳定性
- 客户端不必知道产品内部细节,将产品本身与产品创建过程解耦,使得相同创建过程可以创建不同产品对象
- 可以更加精细控制产品创建过程
- 容易扩展,有新需求可以实现一个新的建造者类来完成
4.6.3.2 缺点
所创建产品具有较多共同点,其组成部分相似,若产品之间差异性大不适合本模式
4.6.4 使用场景
本模式创建的复杂对象,其产品的各个部分经常面临剧烈的变化,但将它们组合一起的算法比较稳定,所以有以下场景
- 创建对象复杂,有多个部件构成,各部件面临复杂变化,但构件间建造顺序是稳定的
- 创建复杂对象算法独立于该对象组成部分及它们的装配方式,即产品的构建过程和最终表示是独立的
4.6.5 案例(组装自行车)
- 抽象建造者
public abstract class Builder {
// 声明Bike类型变量并进行赋值
protected Bike bike = new Bike();
public abstract void buildFrame();
public abstract void buildSeat();
// 构建自行车方法
public abstract Bike createBike();
}
- 具体建造者
public class Mobike extends Builder{
@Override
public void buildFrame() {
bike.setFrame("碳纤维车架");
}
@Override
public void buildSeat() {
bike.setSeat("真皮车座");
}
@Override
public Bike createBike() {
return bike;
}
}
public class OfoBike extends Builder{
@Override
public void buildFrame() {
bike.setFrame("铝合金框架");
}
@Override
public void buildSeat() {bike.setSeat("塑料车座");
}
@Override
public Bike createBike() {
return bike;
}
}
- 具体产品类
public class Bike {
// 车架
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;
}
}
- 指挥者
public class Director {
// 声明builder类型变量
Builder builder ;
public Director(Builder builder) {
this.builder = builder;
}
public Bike bikeConstructor(){
builder.buildSeat();
builder.buildFrame();
return builder.createBike();
}
}
- 测试,结果
public static void main(String[] args) {
Director director = new Director(new Mobike());
Bike bike = director.bikeConstructor();
System.out.println(bike.getFrame());
System.out.println(bike.getSeat());
}
- 类图
4.6.6 扩展
4.6.6.1 问题
当类构造器需要传入较多参数或者有必选参数和非必选参数时,若创建实例则使代码可读性降低,容易发生错误
4.6.6.2 解决
- 代码重构
- 使用链式编程
4.6.6.3 案例(组装电脑)
- 之前
public class Phone {
private String cpu;
private String screen;
private String memory;
private String mainBoard;
public Phone() {
}
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 + '\'' +
'}';
}
}
- 之后
public class Phone {
private String cpu;
private String screen;
private String memory;
private String mainBoard;
// 私有构造方法
private Phone(Builder builder){
this.cpu = builder.cpu;
this.screen = builder.screen;
this.memory = builder.memory;
this.mainBoard = builder.mainBoard;
}
@Override
public String toString() {
return "Phone{" +
"cpu='" + cpu + '\'' +
", screen='" + screen + '\'' +
", memory='" + memory + '\'' +
", mainBoard='" + mainBoard + '\'' +
'}';
}
// 内部类实现链式编程,解决参数传递问题
public static final class Builder{
private String cpu;
private String screen;
private String memory;
private String mainBoard;
public Builder cpu(String cpu){
this.cpu = cpu;
return this; }
public Builder screen(String screen){
this.screen = screen;
return this; }
public Builder memory(String memory){
this.memory = memory;
return this; }
public Builder mainBoard(String mainBoard){
this.mainBoard = mainBoard;
return this; }
public Phone build()
{
return new Phone(this);
}
}
}
- 测试,结果一样,但要是参数更多只用前者来写很容易出现错误,也较为复杂
public static void main(String[] args) {
// 之前
// Phone phone = new Phone("Intel","OL","金士顿","华硕");
// System.out.println(phone);
// 之后
// 创建手机对象,通过构造者对象获取手机对象
Phone phone = new Phone.Builder()
.cpu("Intel")
.screen("OL")
.memory("金士顿")
.mainBoard("华硕")
.build();
System.out.println(phone);
}
4.7 模式对比
4.7.1 工厂方法与建造者
- 工厂方法:注重整体对象创建
- 建造者:注重部件构建过程,意在一步一步精确按照顺序创建一个完整对象
4.7.2 抽象工厂与建造者
- 抽象工厂:实现产品族的创建-----具有不同分类维度的产品组合,采用抽象工厂模式则是不需要关心构建过程,只关心什么产品由什么工厂生产
- 建造者:按照指定图纸构建,通过零部件组装配件而产生一个新产品