设计模式 04 建造者模式
建造者模式(Builder Pattern)属于创建型模式
概述
建造者模式使用多个简单的对象一步一步构建成一个复杂的对象。
一个 Builder 类会一步一步构造最终的对象。该 Builder 类是独立于其他对象的。
经常使用的 StringBuiler
就是建造者模式的典型实现。
代码实现
普通实现
先来看下建造者模式的普通实现。这里模拟快餐店点餐场景:
1、定义快餐食品
/**
* 快餐食品(产品)
*/
public class Product {
/**
* 快餐 A 默认为汉堡
*/
private String BuildA = "汉堡";
/**
* 快餐 B 默认为可乐
*/
private String BuildB = "可乐";
/**
* 快餐 C 默认为薯条
*/
private String BuildC = "薯条";
/**
* 快餐 D 默认为甜点
*/
private String BuildD = "甜点";
public String getBuildA() {
return BuildA;
}
public void setBuildA(String buildA) {
BuildA = buildA;
}
public String getBuildB() {
return BuildB;
}
public void setBuildB(String buildB) {
BuildB = buildB;
}
public String getBuildC() {
return BuildC;
}
public void setBuildC(String buildC) {
BuildC = buildC;
}
public String getBuildD() {
return BuildD;
}
public void setBuildD(String buildD) {
BuildD = buildD;
}
@Override
public String toString() {
return "Product{" +
"BuildA='" + BuildA + '\'' +
", BuildB='" + BuildB + '\'' +
", BuildC='" + BuildC + '\'' +
", BuildD='" + BuildD + '\'' +
'}';
}
}
2、定义厨房
/**
* 厨房(建造者)
*/
public abstract class Kitchen {
/**
* 制作快餐 A
* @param msg 快餐名称
* @return 快餐
*/
abstract Kitchen builderA(String msg);
/**
* 制作快餐 B
* @param msg 快餐名称
* @return 快餐
*/
abstract Kitchen builderB(String msg);
/**
* 制作快餐 C
* @param msg 快餐名称
* @return 快餐
*/
abstract Kitchen builderC(String msg);
/**
* 制作快餐 D
* @param msg 快餐名称
* @return 快餐
*/
abstract Kitchen builderD(String msg);
/**
* 获取产品
* @return 产品
*/
abstract Product getProduct();
}
3、定义服务员
/**
* 服务员(传递者)
*/
public class Waiter extends Kitchen {
private Product product;
public Waiter(){
product = new Product();
}
@Override
Kitchen builderA(String msg) {
product.setBuildA(msg);
return this;
}
@Override
Kitchen builderB(String msg) {
product.setBuildB(msg);
return this;
}
@Override
Kitchen builderC(String msg) {
product.setBuildC(msg);
return this;
}
@Override
Kitchen builderD(String msg) {
product.setBuildD(msg);
return this;
}
@Override
Product getProduct() {
return product;
}
}
4、客人点餐
// 叫服务员
Waiter waiter = new Waiter();
// 可以选择套餐,省事,直接告诉服务员要套餐即可
Product product1 = waiter.getProduct();
System.out.println(product1);
// 也可以自己点餐,点了哪些上哪些
Product product2 = waiter
.builderA("炸鸡")
.builderB("雪碧")
.builderC(null)
.builderD(null)
.getProduct();
System.out.println(product2);
输出结果为:
Product{BuildA='汉堡', BuildB='可乐', BuildC='薯条', BuildD='甜点'}
Product{BuildA='炸鸡', BuildB='雪碧', BuildC='null', BuildD='null'}
如果选择套餐,就按照套餐默认的快餐食品送餐。
如果自己点餐,就按照点的送餐,点了哪些上哪些。
指挥者实现
在工地建筑时,除了建造本身,建造的顺序也非常重要,因此工地上一般都会有一个指挥者来决定建造的顺序。
1、定义一栋楼(产品)
/**
* 一栋楼(产品)
*/
public class Product {
/**
* 地基
*/
private String productA;
/**
* 主体
*/
private String productB;
/**
* 粉刷
*/
private String productC;
/**
* 绿化
*/
private String productD;
public String getProductA() {
return productA;
}
public void setProductA(String productA) {
this.productA = productA;
}
public String getProductB() {
return productB;
}
public void setProductB(String productB) {
this.productB = productB;
}
public String getProductC() {
return productC;
}
public void setProductC(String productC) {
this.productC = productC;
}
public String getProductD() {
return productD;
}
public void setProductD(String productD) {
this.productD = productD;
}
@Override
public String toString() {
return "Product{" +
"productA='" + productA + '\'' +
", productB='" + productB + '\'' +
", productC='" + productC + '\'' +
", productD='" + productD + '\'' +
'}';
}
}
2、定义包工头(抽象建造者)
/**
* 包工头(抽象建造者)
* @author yifan
*/
public abstract class Builder {
/**
* 打地基
*/
abstract void buildA();
/**
* 建主体
*/
abstract void buildB();
/**
* 去粉刷
*/
abstract void buildC();
/**
* 搞绿化
*/
abstract void buildD();
/**
* 建一栋楼
* @return 一栋楼
*/
abstract Product getProduct();
}
3、定义工人(实际建造者)
/**
* 工人(实际建造者)
*/
public class Worker extends Builder{
private Product product;
public Worker() {
// 指定要建设的楼
product = new Product();
}
@Override
void buildA() {
product.setProductA("地基");
System.out.println("地基");
}
@Override
void buildB() {
product.setProductB("主体");
System.out.println("主体");
}
@Override
void buildC() {
product.setProductC("粉刷");
System.out.println("粉刷");
}
@Override
void buildD() {
product.setProductD("绿化");
System.out.println("绿化");
}
@Override
Product getProduct() {
return product;
}
}
4、定义施工调度员(指挥者)
/**
* 施工调度员(指挥者)
*/
public class Director {
/**
* 指挥包工头按照顺序建楼
* @param builder 包工头
* @return 楼
*/
public Product build(Builder builder){
builder.buildA();
builder.buildB();
builder.buildC();
builder.buildD();
return builder.getProduct();
}
}
5、测试
// 施工调度员指挥包工头,包工头找到具体的工人按照施工调度员指定的顺序建造
new Director().build(new Worker());
这样就用代码实现了工地上各岗位的协作,如果工程需要调整建造顺序,只需要更改指挥者的 build 方法即可,非常方便。
设计模式的思想起源于建筑行业,从建造者模式这里就能体现得淋漓尽致。
优缺点
优点
1、建造者独立,易扩展。
2、便于控制细节风险。
缺点
1、产品必须有共同点,范围有限制。
2、如内部变化复杂,会有很多的建造类。
使用场景
1、需要生成的对象具有复杂的内部结构。
2、需要生成的对象内部属性本身相互依赖。
注意事项
与工厂模式的区别是:建造者模式更加关注与零件装配的顺序。
参考
https://www.bilibili.com/video/BV1mc411h719?p=5&vd_source=299f4bc123b19e7d6f66fefd8f124a03
天河有尽身作涯,星海无边前是岸。