建造者模式
-
建造者模式也属于创建型模式,它提供了一种创建对象的最佳方式。
-
定义:
- 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。(同样的造房步骤,我可以建造出平房,我也可以建造出摩天大厦)
-
主要作用:在用户不知道对象的建造过程和细节的情况下就可以直接创建复杂的对象。
-
用户只需要给出指定复杂对象的类型和内容,建造者模式负责按顺序创建复杂对象(把内部的建造过程和细节隐藏起来)
-
例子:
- 工厂(建造者模式):负责制造汽车(组装过程和细节在工厂内)
- 汽车购买者(用户):你只需说出你需要的型号(对象的类型和内容),然后直接购买就可以使用了(不需要知道汽车是怎么组装的(车轮、车门、发动机、方向盘等等))
-
角色分析:
示例:
建图纸(记录建房的方法,步骤):
//抽象的建造者:方法
public abstract class Builder {
abstract void builderA();//地基
abstract void builderB();//钢筋工程
abstract void builderC();//铺电线
abstract void builderD();//粉刷
//完工,得到产品
abstract Product getProduct();
}
创建产品类:
需要哪些零件才能建成房子。
//房子
public class Product {
private String builderA;
private String builderB;
private String builderC;
private String builderD;
public String getBuilderA() {
return builderA;
}
public void setBuilderA(String builderA) {
this.builderA = builderA;
}
public String getBuilderB() {
return builderB;
}
public void setBuilderB(String builderB) {
this.builderB = builderB;
}
public String getBuilderC() {
return builderC;
}
public void setBuilderC(String builderC) {
this.builderC = builderC;
}
public String getBuilderD() {
return builderD;
}
public void setBuilderD(String builderD) {
this.builderD = builderD;
}
@Override
public String toString() {
return "Product{" +
"builderA='" + builderA + '\'' +
", builderB='" + builderB + '\'' +
", builderC='" + builderC + '\'' +
", builderD='" + builderD + '\'' +
'}';
}
}
建工人类(实现图纸的方法,并建出房子):
public class Worker extends Builder{
private Product product;
public Worker() {
this.product = new Product();
}
@Override
void builderA() {
product.setBuilderA("地基");
System.out.println("地基");
}
@Override
void builderB() {
product.setBuilderB("钢筋");
System.out.println("钢筋");
}
@Override
void builderC() {
product.setBuilderC("电线");
System.out.println("电线");
}
@Override
void builderD() {
product.setBuilderD("粉刷");
System.out.println("粉刷");
}
@Override
Product getProduct() {
return product;
}
}
建指挥者类(指挥工人按照什么样的施工顺序干活,并通过工人得到房子)
//指挥者
public class Director {
//指挥工人按照顺序建房子
public Product builder(Builder builder){
builder.builderA();
builder.builderB();
builder.builderC();
builder.builderD();
return builder.getProduct();
}
}
测试类:
public class Test {
public static void main(String[] args) {
Director director = new Director();
Product product = director.builder(new Worker());
System.out.println(product);
}
}
- 上述示例是Builder模式的常规用法,指挥者Director在Builder模式中具有很重要的作用,它用于指挥构建者如何构建产品,控制调用先后次序,并向调用者返回完整的产品类,但是有些情况需要简化系统结构,可以吧Director和抽象建造者进行结合。
- 通过静态内部类方式实现零件无序装配构造,这种方式更加灵活,更符合定义。内部有复杂对象的默认实现,使用时可以根据用户需求自由定义更改内容,并且无需改变具体的构造方式。就可以生产不同复杂产品。
下面进行改造,取消指挥者角色,把选择权交给用户,用户可以选择产品的建造顺序,如果不想自己指挥顺序,则可以拥有默认的产品建造策略。
示例(麦当劳点餐):
解析:顾客可以选择自己组合快餐,也可以直接买默认的套餐。
建抽象的建造者类:
//抽象的建造者
public abstract class Builder {
abstract Builder builderA(String msg);//汉堡
abstract Builder builderB(String msg);//可乐
abstract Builder builderC(String msg);//薯条
abstract Builder builderD(String msg);//甜点
abstract Product getProduct();
}
建产品类(每一个属性被固定的赋值,即为默认的套餐):
//产品
public class Product {
private String builderA="汉堡";
private String builderB="可乐";
private String builderC="薯条";
private String builderD="甜点";
public String getBuilderA() {
return builderA;
}
public void setBuilderA(String builderA) {
this.builderA = builderA;
}
public String getBuilderB() {
return builderB;
}
public void setBuilderB(String builderB) {
this.builderB = builderB;
}
public String getBuilderC() {
return builderC;
}
public void setBuilderC(String builderC) {
this.builderC = builderC;
}
public String getBuilderD() {
return builderD;
}
public void setBuilderD(String builderD) {
this.builderD = builderD;
}
@Override
public String toString() {
return "Product{" +
"builderA='" + builderA + '\'' +
", builderB='" + builderB + '\'' +
", builderC='" + builderC + '\'' +
", builderD='" + builderD + '\'' +
'}';
}
}
建具体的建造者:
public class Worker extends Builder {
private Product product;
public Worker() {
this.product = new Product();
}
@Override
Builder builderA(String msg) {
product.setBuilderA(msg);
return this;
}
@Override
Builder builderB(String msg) {
product.setBuilderB(msg);
return this;
}
@Override
Builder builderC(String msg) {
product.setBuilderC(msg);
return this;
}
@Override
Builder builderD(String msg) {
product.setBuilderD(msg);
return this;
}
@Override
Product getProduct() {
return product;
}
}
测试类:
其中,顾客可以直接选择set方法赋值指定自己想要吃的食品。
如果不想指定,可以直接获取产品,即默认套餐。
public class Test {
public static void main(String[] args) {
//服务员
Worker worker = new Worker();
//默认套餐
// Product product = worker.getProduct();
Product product = worker.builderA("全家桶").builderB("雪碧").getProduct();
System.out.println(product);
}
}
- 优点:
- 产品的建造和表示分离,实现了解耦。使用建造者模式可以使客户端不必知道产品内部组成的细节。
- 将复杂产品的创建步骤分解在不同的方法中使得创建过程更加清晰
- 具体的建造者类之间是相互独立的,这有利于系统的扩展。增加新的具体建造者无需修改原有类库的代码,符合“开闭原则”。
- 缺点:
- 建造者所创建的产品一般具有较多的共同点,其组成部分类似。如果产品之间的差异性很大,则不适合使用建造者模式,因此其使用范围受到一定的限制。
- 如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大。