建造者模式
复杂的对象通常由多个子部件按照一定的顺序组合而成。例如汽车中的发动机、方向盘、车架、轮胎;计算机中的主板、cpu、内存、硬盘等等,但是我们在购买过程中并不需要知道汽车和计算机的组装过程,而我们要做只是付钱,拿到商品而已。这些过程性的操作都是在工厂完成
定义:将一个复杂对象的构建与它的表示分离,使同样的构建过程可以创建不同的表示;
作用:在用户不知道对象的建造过程和细节的情况下就可以直接创建复杂的对象,用户只需要给出指定复杂对象的类型和内容,建造者模式负责按顺序创建复杂对象(把内部的建造过程和细节隐藏起来)
优点:
- 各个具体的建造者相互独立,有利于系统的扩展。增加具体建造者无需修改原有类库的代码,符合"开闭原则"。
- 客户端不必知道产品内部组成的细节,便于控制细节风险。
- 将复杂产品的创建步骤分解在不同的方法中,让创建过程更加清晰。
缺点:
- 产品的组成部分必须相同,这限制了其使用范围。
- 如果产品的内部变化复杂,该模式会增加很多的建造者类。
建造者(Builder)模式和工厂模式的区别:
- 建造者模式注重零部件的组装过程
- 工厂方法模式更注重零部件的创建过程
例子:
-
工厂(建造者模式):负责制造汽车(组装过程和细节都在工厂内完成)
-
汽车购买者(用户):只需要说出需要的汽车型号和具体配置(对象的类型和内容),然后直接购买就可以使用了(不需要知道汽车是怎么组装的(汽车的生产过程))
1.模式结构图
- 模式实现一图
- 模式实现二图
2.模式的结构
-
产品角色:它是包含多个组成部件的复杂对象,由具体建造者来创建其各个子部件。
-
抽象建造者:它是一个包含创建产品各个子部件的抽象方法的接口,通常还包含一个返回复杂产品的方法。
-
具体建造者:实现 Builder 接口,完成复杂产品的各个部件的具体创建方法。
-
指挥者:它调用建造者对象中的部件构造与装配方法完成复杂对象的创建,在指挥者中不涉及具体产品的信息。
3.模式的实现一
-
产品角色:
/** * 产品类:房子 */ public class Product { private String buildA; private String buildB; private String buildC; private String buildD; public String getBuildA() { return buildA; } //getter/setter此处省略... @Override public String toString() { return "Product{" + "buildA='" + buildA + '\'' + ", buildB='" + buildB + '\'' + ", buildC='" + buildC + '\'' + ", buildD='" + buildD + '\'' + '}'; } }
-
抽象建造者:
/**
* 建造者抽象类
*/
public abstract class Builder {
//地基
abstract void buildA();
//钢精
abstract void buildB();
//水泥
abstract void buildC();
//粉刷
abstract void buildD();
//完工 :得到产品
abstract Product getProduct();
}
- 具体建造者:
/**
* 具体建造者:工人类
*/
public class Worker extends Builder {
private Product product;
//注意这里的无参构造用来创建抽象产品实例对象
public Worker() {
this.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;
}
}
- 指挥者
/**
* 指挥者:负责指挥一个工程的构建
*/
public class Director {
//指挥工人按照顺序建房子
public Product build(Builder builder){
builder.buildA();
builder.buildB();
builder.buildC();
builder.buildD();
return builder.getProduct();
}
}
-
测试结果:
public class BuilderFactoryClient { public static void main(String[] args) { Director director = new Director(); Product build = director.build(new Worker()); System.out.println(build); } } /*================= 输出结果================ 地基 钢精 水泥 粉刷 Product{buildA='地基', buildB='钢精', buildC='水泥', buildD='粉刷'} ================= 输出结果================*/
4.模式的实现二
模式实现一是建造者模式的常规用法,指挥者Director在建造者模式中具有很重要的作用,它用于指导具体构建者该如何构建产品,控制子部件的调用顺序,并且返回完整的产品类,但是有些情况下需要简化接通结构,就可以把Director和抽象建造者进行结合。
通过静态内部类方式实现零件无序装配构造,这种方式使用更加灵活,更符合定义。内部复杂对象的默认实现,使用时可以根据用户需求自由定义更改内容,并且无需改变具体的构造方式。就可以产生出不同复杂产品。
比如:麦当劳的套餐,服务员(具体建造者)可以搭配任意几种产品(零件)组成一款套餐(产品),然后出售给客户。比第一种方式少了指挥者,主要是因为第二种方式把指挥者交给用户来操作,使得产品的创建更加简单灵活。
-
产品角色
/** * 产品类: 套餐 */ public class Product { //默认套餐类型 private String buildA = "汉堡"; private String buildB = "可乐"; private String buildC = "薯条"; private String buildD = "甜品"; //getter/setter此处省略... @Override public String toString() { return "Product{" + "buildA='" + buildA + '\'' + ", buildB='" + buildB + '\'' + ", buildC='" + buildC + '\'' + ", buildD='" + buildD + '\'' + '}'; } }
-
抽象建造者
/** * 建造者抽象类 */ public abstract class Builder { //主食 abstract Builder buildA(String msg); //饮料 abstract Builder buildB(String msg); //副餐 abstract Builder buildC(String msg); //甜品 abstract Builder buildD(String msg); //完工 :得到产品 abstract Product getProduct(); }
-
具体建造者
/** * 具体建造者: 服务员类 */ public class Worker extends Builder { private Product product; public Worker() { this.product = new Product(); } @Override Builder buildA(String msg) { product.setBuildA(msg); return this; } @Override Builder buildB(String msg) { product.setBuildB(msg); return this; } @Override Builder buildC(String msg) { product.setBuildC(msg); return this; } @Override Builder buildD(String msg) { product.setBuildD(msg); return this; } @Override Product getProduct() { return product; } }
-
测试结果:
/** * 客户类 */ public class BuilderFactoryClient { public static void main(String[] args) { //没有指挥者,由服务员自己来创建套餐 Worker worker = new Worker(); Product build = worker.getProduct(); System.out.println("顾客没有选择,推荐默认套餐:"); System.out.println(build); System.out.println("====================分割线=================="); System.out.println("顾客选择自定义套餐,推荐默认套餐:"); //顾客主食点了鸡肉卷 build.setBuildA("鸡肉卷"); //顾客饮料点了芬达 build.setBuildB("芬达"); System.out.println(build); } } /*================= 输出结果================ 顾客没有选择,推荐默认套餐: Product{buildA='汉堡', buildB='可乐', buildC='薯条', buildD='甜品'} ====================分割线================== 顾客选择自定义套餐,推荐默认套餐: Product{buildA='鸡肉卷', buildB='芬达', buildC='薯条', buildD='甜品'} ================= 输出结果================*/
5.模式的应用场景
建造者(Builder)模式创建的是复杂对象,其产品的各个部分经常面临着剧烈的变化,但将它们组合在一起的算法却相对稳定,所以它通常在以下场合使用。
- 需要生产的产品对象有复杂的内部结构,这些产品对象具备共性。
- 隔离复杂对象的创建和使用,并且使用相同的创建过程可以创建不同的产品。
- 具有较多零件(属性)的产品(对象)的创建过程