建造者模式

实现一个汽车模型,可以由客户任意调整零件顺序


实现类图

car_model.png

1.先定义一个CarModel类,实现汽车的整体模型:
public abstract class CarModel {
    //记录零件步骤
    private ArrayList<String> sequence = new ArrayList<>();

    //设置步骤方法,并交给子类去实现
    protected abstract void start();

    protected abstract void stop();

    protected abstract void alarm();

    protected abstract void engineBoom();

    //运行汽车,设置为final类型,防止被子类修改
    final public void run(){
        for (int i = 0; i < this.sequence.size(); i ++){
            String actionName = this.sequence.get(i);
            if (actionName.equalsIgnoreCase("start")){
                this.start();
            } else if (actionName.equalsIgnoreCase("stop")){
                this.stop();
            } else if (actionName.equalsIgnoreCase("alarm")){
                this.alarm();
            } else if (actionName.equalsIgnoreCase("engine boom")){
                this.engineBoom();
            }
        }
    }
    //设置步骤过程
    final public void setSequence(ArrayList sequence){
        this.sequence = sequence;
    }

}
2. 分别实现具体的汽车模型-宝马和奔驰
package original;

/**
 * Created by Administrator on 2017/3/9/009.
 * 实现奔驰车的零件
 */
public class BenzModel extends CarModel {
    @Override
    protected void start() {
        System.out.println("奔驰车的声音是这样的....");
    }

    @Override
    protected void stop() {
        System.out.println("奔驰车是这样停车的....");
    }

    @Override
    protected void alarm() {
        System.out.println("奔驰车的喇叭声音是这样的....");
    }

    @Override
    protected void engineBoom() {
        System.out.println("奔驰车的引擎声音是这样的....");
    }
}


package original;

/**
 * Created by Administrator on 2017/3/9/009.
 * 实现宝马车的零件
 */
public class BMWModel extends CarModel {
    @Override
    protected void start() {
        System.out.println("宝马车跑起来是这样的....");
    }

    @Override
    protected void stop() {
        System.out.println("宝马停车是这样的....");
    }

    @Override
    protected void alarm() {
        System.out.println("宝马车喇叭声是这样的....");
    }

    @Override
    protected void engineBoom() {
        System.out.println("宝马车引擎声是这样的....");
    }
}
3. 客户可以根据自己的需求定义零件的顺序:
public class Client {
    public static void main(String[] args){
        //满足需求,可以由客户调整步骤
        BenzModel benz = new BenzModel();
        ArrayList<String> sequence = new ArrayList<>();
        sequence.add("engine boom");
        sequence.add("start");
        sequence.add("stop");
        benz.setSequence(sequence);
        benz.run();
    }
}
问题是我们这样做只满足和一个需求,如果出现更多的需求呢?因此,我们要设计一个中新的模式:为每种模型产品模型定义一个建造者,要什么顺序,由建造者来建造。

设计类图:

Paste_Image.png

1. 定义一个父类建造者
/**
 * Created by Administrator on 2017/3/9/009.
 * 定义一个汽车建造者父类
 */
public abstract class CarBuilder {
    //设置零件顺序
    public abstract void setSequence(ArrayList<String> sequence);
    //获取到汽车模型
    public abstract CarModel getCarModel();
}
2. 构建具体的奔驰建造者和宝马建造者
/**
 * Created by Administrator on 2017/3/9/009.
 * 实现具体的奔驰建造者
 */
public class BenZBuilder extends CarBuilder {
    //获取到一个奔驰引用
    private BenzModel benz = new BenzModel();
    //设置其零件顺序
    @Override
    public void setSequence(ArrayList<String> sequence) {
        this.benz.setSequence(sequence);
    }
    //返回当前奔驰模型
    @Override
    public CarModel getCarModel() {
        return this.benz;
    }
}

public class BMWBuilder extends CarBuilder {
    private BMWModel bmw = new BMWModel();
    @Override
    public void setSequence(ArrayList<String> sequence) {
        this.bmw.setSequence(sequence);
    }

    @Override
    public CarModel getCarModel() {
        return this.bmw;
    }
}
3. 客户再次调用,只要将顺序交给建造者,就可以建造出相应的模型出来
public static void main(String[] args){
        //设置零件顺序
        ArrayList<String> sequence = new ArrayList<>();
        sequence.add("engine boom");
        sequence.add("start");
        sequence.add("stop");
        //创建建造者
        BenZBuilder builder = new BenZBuilder();
        //将零件顺序传递给建造者
        builder.setSequence(sequence);
        //根据零件顺序创建出既定的模型
        BenzModel benz = (BenzModel) builder.getCarModel();
        benz.run();
    }
4. 封装建造者,我们建立一个导演对象,指定各个事件的顺序,然后为每种顺序都指定一个代码,以便即可生产出对应的模型。

设计类图

Paste_Image.png

a. 建立导演对象:


public class Director {
    //定义顺序列表和建造者
    private ArrayList<String> sequence = new ArrayList<>();
    private BenZBuilder benZBuilder = new BenZBuilder();
    private BMWBuilder bmwBuilder = new BMWBuilder();

    //通过建造者实现各种不同类型的汽车模型
    public BenzModel getABenZModel(){
        this.sequence.clear();
        this.sequence.add("start");
        this.sequence.add("stop");
        this.benZBuilder.setSequence(this.sequence);
        return (BenzModel) this.benZBuilder.getCarModel();
    }

    public BenzModel getBBenZModel(){
        this.sequence.clear();
        this.sequence.add("engine boom");
        this.sequence.add("start");
        this.sequence.add("stop");
        this.benZBuilder.setSequence(this.sequence);
        return (BenzModel) this.benZBuilder.getCarModel();
    }

    public BMWModel getCBMWModel(){
        this.sequence.clear();
        this.sequence.add("alarm");
        this.sequence.add("start");
        this.sequence.add("stop");
        this.bmwBuilder.setSequence(this.sequence);
        return (BMWModel) this.bmwBuilder.getCarModel();
    }

    public BMWModel getDBMWModel(){
        this.sequence.clear();
        this.sequence.add("start");
        this.bmwBuilder.setSequence(this.sequence);
        return (BMWModel) this.bmwBuilder.getCarModel();
    }
}

b. 这样我们就可以批量地生产各种不同种类型了,当需要增加类型时,只需在Director中添加即可生产。

  public static void main(String[] args){
        Director director = new Director();

        for (int i = 0; i < 10; i ++){
            director.getABenZModel().run();
        }

        for (int i = 0; i < 10; i ++){
            director.getBBenZModel().run();
        }

        for (int i = 0; i < 10; i ++){
            director.getCBMWModel().run();
        }
    }

建造者模式:将一个复杂的对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。


1. 通用类图:

Paste_Image.png

2. 角色:

a. Product类:
通常实现了模板方法模式,其中BenzModel和BMWModel就属于产品类。
b. Builder抽象建造者:
规范产品的组建,一般由子类实现,其中CarBuilder就是抽象建造者。
c. ConcreteBuilder具体建造者:
实现抽象类定义的所有方法,并且返回一个组建好的对象,其中BenzBuilder就属于具体建造者。
d. Director导演类:
负责安排已有的模板的顺序,然后告诉Builder开始建造。


3. 建造者模式的优点:

a. 封装性:
使用建造者模式可以使客户端不必知道产品内部组成的细节。
b. 建造者独立,易于扩展。
c. 便于控制细节风险:
由于具体的建造者是独立的,因此对于建造过程逐步细化,而不对其他的模块产生任何影响。


  1. 建造者的使用场景

a. 相同的方法,不同的执行顺序,产生不同的事件结果。
b. 多个部件或零件,都可以装配到一个对象中,但是产生的运行结果又不相同。
c. 产品类非常复杂,或者产品类中的调用顺序不同产生了不同的效能。


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,636评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,890评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,680评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,766评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,665评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,045评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,515评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,182评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,334评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,274评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,319评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,002评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,599评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,675评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,917评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,309评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,885评论 2 341

推荐阅读更多精彩内容