您的位置:首页 > 产品设计 > UI/UE

第六篇、创建型设计模式——建造者(Builder)模式/生成器模式

2017-03-07 15:57 615 查看
建造者(Builder)模式又可以称为生成器模式,它是将一个复杂对象的构建与它的表示进行分离,使得同样的构建过程可以创建不同的表示。

那么,怎么理解这句话呢,其实说白了就是:当我们需要创建一个比较复杂的对象,并且,这个对象的创建过程比较稳定,那么,我们只需要通过指定这个对象的类型与内容,就可以一步一步的创建出这个复杂的对象,而无需知道这个对象内部的具体组装细节。

我们还是通过举例来进行描述。

大家都在外面吃过饭,相信都会遇到这样的情况,同样的一份木须肉,我们去不同的店,有的好吃,有的难吃。我们去麦当劳吃巨无霸汉堡,无论去那个店,味道基本一样。这是因为什么呢。用我们前面说过的一个原则解释,就是依赖倒转原则。就麦当劳而言,其对巨无霸汉堡的制作抽象出了一套流程,不管是哪个店,都要按照这个流程进行加工,其加工细节有具体的操作人员进行把控。然而作为木须肉,每家店都有自己的做法,缺少一套标准的制作流程,因此有些店做的好吃,有些店做的难吃。

麦当劳制作汉堡的过程,可以看做是建造者模式的一种体现:

1、首先,麦当劳有一款产品是汉堡

public class Hamburgers {
private List<String> parts = new ArrayList<>();

public void addPart(String part) {
parts.add(part);
}

public void show() {
StringBuffer buffer = new StringBuffer();
buffer.append("汉堡组成材料有");
for (String p : parts) {
buffer.append("/" + p);
}
System.out.println(buffer.toString());
}

}
它有着自己的组成原料parts。

2、麦当劳为了将汉堡做的好吃,抽象出了一套成功的标准制作流程:

public abstract class Builder {
public abstract void buildPartA();
public abstract void buildPartB();
public abstract void buildPartC();
public abstract void buildPartD();
public abstract Hamburgers getResult();
}
这套流程需要ABCD四步加工组装,从而获得成熟产品(getResult)。

3、具体的加工细节有专门的人负责(具体的创建者类):

public class HamburgersBuilder extends Builder {
Hamburgers hamburgers = new Hamburgers();

@Override
public void buildPartA() {
System.out.println("准备两个面包片");
hamburgers.addPart("两个面包片");
}

@Override
public void buildPartB() {
System.out.println("在面包片中间放上肉片");
hamburgers.addPart("肉片");
}

@Override
public void buildPartC() {
System.out.println("在肉片上放上蔬菜");
hamburgers.addPart("蔬菜");
}

@Override
public void buildPartD() {
System.out.println("在蔬菜上涂抹上酱料");
hamburgers.addPart("酱料");

}

@Override
public Hamburgers getResult() {
return hamburgers;
}
}
4、还有一个指挥者在旁指挥,帮助产品顺利的制作成功:
public class Director {
public void construct(Builder builder){
builder.buildPartA();
builder.buildPartB();
builder.buildPartC();
builder.buildPartD();
}
}
指挥者要求,制作过程必须按照ABCD的顺序进行加工。

5、当客户需要汉堡时:

Director director = new Director(); //找到指挥者
Builder hbgBuilder = new HamburgersBuilder(); //找到汉堡细节加工者

director.construct(hbgBuilder); //指挥者指挥汉堡加工者进行加工
Hamburgers hamburgers = hbgBuilder.getResult(); //获得汉堡
hamburgers.show();


这就是建造者模式的构架方式,大家可能没发现这个模式有什么优势,感觉绕来绕去的,还没有直接创建来得简单。
其实不然,首先,这种面向接口的编写方式,排除了可能因为失误所造成的产品残缺的问题,比如少加了调料,导致汉堡变难吃了。因为有抽象接口的约束,是加工人员知道,哪些步骤是必不可少的,避免了步骤遗漏。

然后呢,它的好处就是隐藏了产品的组装过程,使得客户无需知道其制作流程就可得到想要的产品。当需要添加新的同类产品,只需要再定义一个具体建造者就可以了。例如添加麦辣鸡腿汉堡,组装流程不变,材料及细节调整就好。

那么,什么时候我们要用到建造者模式呢?

当我们需要创建一些比较复杂的对象,这些对象的构建过程比较稳定,但是内部细节可能面临复杂的变化时,就要考虑运用此模式了。

建造者模式还有一个变种,相信大家也看到过,我们一起来看看。

大家都吃过砂锅米线吧,简单来说,一份砂锅米线必不可少的就是米线和一些基本配料,然后根据个人需要,可以选择性的添加配料,味道也可以选择原味的,微辣、中辣以及超辣。我们按照这个例子来运用一下变种Builder

首先,就是我们的米线类

public class MiXian {
private List<String> parts;

public MiXian(Builder builder) { //米线构造类听过接收Builder进行内容配置
this.parts = builder.parts;
}

public void show() {
StringBuffer buffer = new StringBuffer();
buffer.append("米线组成材料有");
for (String p : parts) {
buffer.append("/" + p);
}
System.out.println(buffer.toString());
}

public static final class Builder { //米线的静态内部类Builder
List<String> parts = new ArrayList<>();

public Builder() { //其构造器部分是砂锅米线必有的
System.out.println("米线下锅 + 添加基本配料");
parts.add("米线");
parts.add("基本配料");
}

public Builder buildPartA() { //可选组成A
System.out.println("另外添加配料一份");
parts.add("额外配料");
return this;
}

public Builder buildPartB() { //可选组成B
System.out.println("不放辣椒——做成原味");
return this;
}

public Builder buildPartC() { //可选组成C
System.out.println("放少量辣椒——做成微辣");
parts.add("少量辣椒");
return this;
}

public Builder buildPartD() { //可选组成D
System.out.println("放中量辣椒——做成中辣");
parts.add("中量辣椒");
return this;
}

public Builder buildPartE() { //可选组成E
System.out.println("放大量辣椒——做成超辣");
parts.add("大量辣椒");
return this;
}

public MiXian build() {
return new MiXian(this);
}
}
}然后我们在客户端调用时,可以这样写:
MiXian miXian = new MiXian.Builder().buildPartA().buildPartC().build();
miXian.show();

是不是很熟悉的写法,一个方法链,其中的buildPartA、B、C、D、E都是可以根据个人需要进行选择性组装,从而获得拥有各自特点的产品对象。做Android开发的小伙伴会发现,其在Android中的应用比较广泛,比如AlertDialog:
new AlertDialog.Builder(this)
.setTitle("提示")
.setMessage("XXXXXXXXXXX")
.setIcon(R.drawable.XX)
.setCancelable(true)
.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
//...
}
})
.show();

是不是用的很多!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息