设计模式——建造者模式
本片文章总结于《狂神说Java》的设计模式篇章:
B站链接
一、建造者模式
简介:
建造者模式提供了一种创建对象的一种最佳的方法
作用
将一个复杂的对象的构建于他的表示进行分离,通过同样的构建方式可以创建出不同的方法。(例如造房子,可以通过大体的步骤:地基 —> 钢筋 —> 电线 —> 水泥创建出不同的房子,但大体步骤相似)
用户在不需要知道对象创建的建造过程和细节就可以直接创建对象
二、具体实现
1.类图
- Director:监管者,类似于造房子的包工头(也是核心,因为他设计到建造的一个整体顺序和流程是如何进行的)
- Build:大体要进行哪些步,类似造房子的图纸
- 具体的Build:具体的实现过程,建造的具体过程
- Produce:最终的产品
2.案例实现
首先定义最终获得的产品Product
public class Product {
private String buildA;
private String buildB;
private String buildC;
private String buildD;
public String getBuildA() {
return buildA;
}
public void setBuildA(String buildA) {
this.buildA = buildA;
}
public String getBuildB() {
return buildB;
}
public void setBuildB(String buildB) {
this.buildB = buildB;
}
public String getBuildC() {
return buildC;
}
public void setBuildC(String buildC) {
this.buildC = buildC;
}
public String getBuildD() {
return buildD;
}
public void setBuildD(String buildD) {
this.buildD = buildD;
}
@Override
public String toString() {
return "Product{" +
"buildA='" + buildA + '\'' +
", buildB='" + buildB + '\'' +
", buildC='" + buildC + '\'' +
", buildD='" + buildD + '\'' +
'}';
}
}
接着定义一个抽象的Build,里面只涉及到创建的大体步骤过程
public abstract class Builder {
abstract void buildA();//地基
abstract void buildB();//钢筋
abstract void buildC();//电线
abstract void buildD();//水泥
// 得到产品
abstract Product getProduct();
}
定义一个Work具体实现Build,即创建房子的工人,每一步需要进行什么工作
注意:Worker构造类里面没有参数,内部自己new一个,用户不需要自己建造
public class Worker extends Builder {
private Product product;
// 工人负责创建产品,不是外部在传进来
public Worker(){
product = new Product();
}
@Override
void buildA() {
product.setBuildA("地基");
System.out.println("地基");
}
@Override
void buildB() {
product.setBuildB("钢筋");
System.out.println("钢筋");
}
@Override
void buildC() {
product.setBuildC("电线");
System.out.println("电线");
}
@Override
void buildD() {
product.setBuildD("水泥");
System.out.println("水泥");
}
@Override
Product getProduct() {
return product;
}
}
监工,告诉Work的工作顺序
public class Director {
// 指挥工作
public Product build(Builder builder){
builder.buildA();
builder.buildB();
builder.buildC();
builder.buildD();
return builder.getProduct();
}
}
测试
public class Test {
public static void main(String[] args) {
// 监工
Director director= new Director();
// 指挥具体工人
Product build = director.build(new Worker());
System.out.println(build.toString());
}
}
运行结果
三、建造者模式与内部类结合(Build的链式编程)
上述的建造者过程有一个Director的角色用于指挥整体的创建过程以及调用顺序,并在最后返回产品,但有些情况下我们需要简化这个过程,将Director与抽象建造这进行结合,例如点餐,可以有默认套餐,也可以我们任意搭配自选。
通过静态内部类方法实现无序的装配构造形式,这种方式更灵活自由,更加符合定义。内部有默认的方法实现,也可以根据需求自定义更改,从而生产出不同的复杂的产品。
产品类(与上面不同的是这次产品有了默认的值)
public class Product {
// 一些默认的内容
private String BuildA = "汉堡";
private String BuildB = "薯条";
private String BuildC = "可乐";
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 + '\'' +
'}';
}
}
抽象的Build类
public abstract class Builder {
abstract Builder builderA(String builderA);
abstract Builder builderB(String builderB);
abstract Builder builderC(String builderC);
abstract Builder builderD(String builderD);
abstract Product getProduct();
}
具体Worker(构造方法还是一样,返回新对象,但不同的是可以对产品的属性进行set)
public class Work extends Builder{
Product product;
public Work(){
product = new Product();
}
@Override
Builder builderA(String builderA) {
product.setBuildA(builderA);
return this;
}
@Override
Builder builderB(String builderB) {
product.setBuildA(builderB);
return this;
}
@Override
Builder builderC(String builderC) {
product.setBuildA(builderC);
return this;
}
@Override
Builder builderD(String builderD) {
product.setBuildD(builderD);
return this;
}
@Override
Product getProduct() {
return product;
}
}
测试
public class Test {
public static void main(String[] args) {
Work work = new Work();
// 链式编程
Product product = work.builderA("鸡翅").builderD("蛋挞")
.getProduct();
System.out.println(product.toString());
}
}
运行结果
建造者模式与抽象工厂模式的对比
- 与抽象工厂模式相比,建造者模式返回一个组装好的完整产品,而抽象工厂模式返回的是**一系列相关的产品,**这些产品位于不同的产品等级结构,构成一个产品族。(比如抽象工厂可能返回的是某个具体工厂里面生产的不同产品,例如小米工厂生产手机和路由器,这两个不是同一个产品等级,但是构成产品族)。
- 在抽象工厂中,客户端实例化工厂,调用工厂方法获得所需要的对象;而在建造者模式之中,可以不直接调用建造者的相关方法,调用指挥者类指导如何生产对象(即上述中不调用Worker,而是调用Director去完成),包括对象的组装过程和建造的步骤,侧重于一步一步构建一个复杂的对象(链式编程),返回一个完整的对象。
- 如果将抽象工厂模式看作是汽车配件生产厂,生产一个产品族的产品,那么建造者模式就是一个汽车的组装工厂,通过组装返回一个完整汽车
总结
优点:
- 产品的构建与他的表示进行分离,实现了解耦。使用者不必知道产品内部的组成细节
- 将复杂的创建步骤分解在不同的方法之中,使得创建更为简单
- 具体的建造者类之间是相互独立的,这有利于系统的扩展。增加新的具体建造者无需改变原有代码,符合开闭原则
缺点:
- 建造者模式所创建的产品一般都有比较多的共同点,其组成部分相似;如果产品之间的差异性比较大,不适合使用
- 如果产品内部结构比较复杂,可能会需要定义比较多的具体建造者来实现这种变化,导致系统变得很庞大
使用场景:
- 生产的产品有复杂的内部结构,但他们具有共性
- 隔离复杂对象的创建和使用,并使得相同的创建过程可以创建出不同的产品
- 适用于一个具有较多的零件(属性)的产品(对象)的创建过程