Java设计模式4之建造者模式(光头强买电锯引发的思考)

本文根据光头强做电锯的故事,讲解一下Java设计模式中的“建造者模式”,故事性更强,配合着代码讲解,让大家更轻松的掌握“建造者模式”。


一、故事背景

熊出没 第59集 超级电锯

本文示例代码请查看Github:https://github.com/AweiLoveAndroid/CommonDevKnowledge/tree/master/design_patterns

(一)什么是建造者模式?

建造者模式它是一种将复杂对象的构造与其表示分开,以便相同的构造过程可以创建不同的表示的设计模式。

(二)基本组成单元有哪些?

一个完整的建造者模式分为4个部分:

  • 1.建造者(Builder):用于创建Product对象的部分的抽象接口。
  • 2.具体建造者(ConcreteBuilder):通过实现Builder接口构建和组装产品的一部分。
  • 3.指挥者(Director):它直接Builder接口来构造对象。
  • 4.产品(Product):需要构建的复杂的对象。

(三)主要作用

减少构造器或者方法调用的传入。

(四)使用场景

一般用于复杂的对象内部,比如:一个对象有多个功能,可以在它的内部用多个方法具体描述每个功能,然后调用这个类的时候,就可以直自由的构建出这个类对象(比如:new Person().setName("18").setAge(20).build();其实这个Person类就做了具体的对象构建的操作逻辑。),也有网友狭隘的说链式调用就是建造者模式,其实那是片面的认识,虽然是一种表现形式,但是实际操作中有很多不同的表现形式,不能一概而论。下面就一个实例详解一下基本使用到复杂多变的使用场景。


二、基本使用场景

(一)各个类的介绍:

光头强于是去了镇子上的五金店铺,,光头强心理嘀咕着:“不光能砍树,还能吓跑熊大熊二,看它还敢来欺负自己。”于是跟那个老板的说了自己的需求:“我要买一把电手锯”。老板说:“不好意思,没有了,需要预定,预计一个星期之后就到了。”然后光头强就下单了,老板就电话通知手电锯工厂下了订单,然后工厂开始生产手电锯。

这回还没把熊大熊二吓跑,于是光头强又跑到镇子上,找到了五金店的老板,让老板给他一把厉害的锯子。光头强这回跟那个老板的说了自己的需求:“我要一把厉害的电手锯,上回那个没有赶走熊大熊二,你这里有没有厉害的手电锯”。老板逐个都介绍了一遍,光头强一对比,发现并没有自己想要的独一无二的那个。于是跟那个老板的说了自己的需求:“我需要的是这样的:调速防误触智能开关、动力强耐高温散热好的纯铜电机、环保大容量锂电池、人体工体学包胶防滑防抖手柄、环保防触电插头、加厚加固耐磨抗打击防护罩、高硬度锯片、然后额外配上LED灯,钱不是问题”。老板说没问题,半个月之后过来取吧。光头强于是交了定金,兴奋的回家了。坐等老板的好消息了。

车间要准备要投入生产的机器,还有各种原材料和模具:

/**
 * 链锯建筑者
 */
public interface ChainsawBuilder {
    // 蓄电池
    void battery();
    // 电动机
    void motor();
    // 减速箱
    void reductionGearbox();
    // 防护罩
    void hood();
    // 手柄
    void handle();
    // 开关
    void switches();
    // 插头
    void plug();
    // 圆锯片
    void circularSaw();

    // 获取链锯(产品)的实例
    Chainsaws getChainsaws();

}

接下来就是具体的车间按照现有的材料进行生产:

/**
 * 链锯建筑者(具体建筑者)
 */
public class ChainsawBuilderImpl implements ChainsawBuilder{

    private Chainsaws chainsaws;

    public ChainsawBuilderImpl() {
        chainsaws = new Chainsaws();
    }


    @Override
    public void battery() {
        chainsaws.setBattery("普通锂电池");
    }

    @Override
    public void motor() {
        chainsaws.setMotor("普通铝电动机");
    }

    @Override
    public void reductionGearbox() {
        chainsaws.setReductionGearbox("普通减速箱");
    }

    @Override
    public void hood() {
        chainsaws.setHood("普通PVC塑料");
    }

    @Override
    public void handle() {
        chainsaws.setHandle("普通PVC塑料");
    }

    @Override
    public void switches() {
        chainsaws.setSwitches("普通拉线开关");
    }

    @Override
    public void plug() {
        chainsaws.setPlug("普通三口插头");
    }

    @Override
    public void circularSaw() {
        chainsaws.setCircularSaw("普通钢锯片");
    }

    @Override
    public Chainsaws getChainsaws() {
        return chainsaws;
    }
}

最终产品就具备这些功能:

/**
 * 产品(链锯)
 */
public class Chainsaws {

    // 蓄电池
    private String battery;
    // 电动机
    private String motor;
    // 减速箱
    private String reductionGearbox;
    // 防护罩
    private String hood;
    // 手柄
    private String handle;
    // 开关
    private String switches;
    // 插头
    private String plug;
    // 圆锯片
    private String circularSaw;


    public String getBattery() {
        return battery;
    }

    public void setBattery(String battery) {
        this.battery = battery;
    }

    public String getMotor() {
        return motor;
    }

    public void setMotor(String motor) {
        this.motor = motor;
    }

    public String getReductionGearbox() {
        return reductionGearbox;
    }

    public void setReductionGearbox(String reductionGearbox) {
        this.reductionGearbox = reductionGearbox;
    }

    public String getHood() {
        return hood;
    }

    public void setHood(String hood) {
        this.hood = hood;
    }

    public String getHandle() {
        return handle;
    }

    public void setHandle(String handle) {
        this.handle = handle;
    }

    public String getSwitches() {
        return switches;
    }

    public void setSwitches(String switches) {
        this.switches = switches;
    }

    public String getPlug() {
        return plug;
    }


    public void setPlug(String plug) {
        this.plug = plug;
    }

    public String getCircularSaw() {
        return circularSaw;
    }

    public void setCircularSaw(String circularSaw) {
        this.circularSaw = circularSaw;
    }


    @Override
    public String toString() {
        return "Chainsaws{" +
                "\n battery='" + battery + '\'' +
                ", motor='" + motor + '\'' +
                ", reductionGearbox='" + reductionGearbox + '\'' +
                ", hood='" + hood + '\'' +
                ", handle='" + handle + '\'' +
                ", switches='" + switches + '\'' +
                ", plug='" + plug + '\'' +
                ", circularSaw='" + circularSaw + '\'' +
                "链锯已经做好了\n" + '}';
    }


}

老板作为一个中间人的角色,需要跟厂商对接,电话通知建造方,查看进度如何了:

/**
 * 五金店老板(验收方)
 */
public class HardwareStoreBoss {

    // 电话通知建造方,查看进度如何了
    public Chainsaws notify(ChainsawBuilder builder){

        // 蓄电池
        builder.battery();
        // 电动机
        builder.motor();
        // 减速箱
        builder.reductionGearbox();
        // 防护罩
        builder.hood();
        // 手柄
        builder.handle();
        // 开关
        builder.switches();
        // 插头
        builder.plug();
        // 圆锯片
        builder.circularSaw();
        return builder.getChainsaws();
    }
}

过了几天,光头强打电话给五金店老板。

HardwareStoreBoss hardwareStoreBoss = new HardwareStoreBoss();

五金店老板跟光头强说你等会儿,我先去问问链锯做好了没,于是:

  Chainsaws chainsaws = hardwareStoreBoss.notify(new ChainsawBuilderImpl());
        System.out.println(chainsaws.toString());

这时候打印结果是:

Chainsaws{
 battery='普通锂电池', motor='普通铝电动机', reductionGearbox='普通减速箱', hood='普通PVC塑料', handle='普通PVC塑料', switches='普通拉线开关', plug='普通三口插头', circularSaw='普通钢锯片'链锯已经做好了
}

然后五金店老板去生产那里取货,然后再通知光头强过去取货。

(二)UML图解如下:


三、新增建造者接口(换一个新链锯)

(一)各个类的介绍:

光头强拿到货之后,就兴高采烈的去试着砍树,结果发现砍了几棵树,要么就是没电了,要么就是掉链子了,这怎么行?光头强这回要求老板退货,老板不干,这样吧。我给你返回维修。维修费我出。光头强不干,坚决要退货,老板犟不过,要不这样,给你换一个性能更高级的链锯,你只要补差价就好了,怎么样,工厂那边正好有批次在做的,给你预定一个,一周内可以就拿到货了。光头强爽快的答应了。

于是工厂这边也利用原有的功能(接口ChainsawBuilder),加入新的一些功能(新建一个类ChainsawBuilderImpl2),就开始制造了。基本功能都差不多的,只是换一些零部件,如下所示:

/**
 * 链锯建筑者(具体建筑者)
 */
public class ChainsawBuilderImpl2 implements ChainsawBuilder{

    private Chainsaws chainsaws;

    public ChainsawBuilderImpl2() {
        chainsaws = new Chainsaws();
    }


    @Override
    public void battery() {
        chainsaws.setBattery("环保大容量锂电池");
    }

    @Override
    public void motor() {
        chainsaws.setMotor("动力强耐高温散热好的纯铜电机");
    }

    @Override
    public void reductionGearbox() {
        chainsaws.setReductionGearbox("减震变频高功率变速箱");
    }

    @Override
    public void hood() {
        chainsaws.setHood("加厚加固耐磨抗打击防护罩");
    }

    @Override
    public void handle() {
        chainsaws.setHandle("人体工体学包胶手柄");
    }

    @Override
    public void switches() {
        chainsaws.setSwitches("调速防误触智能开关");
    }

    @Override
    public void plug() {
        chainsaws.setPlug("环保防触电插头");
    }

    @Override
    public void circularSaw() {
        chainsaws.setCircularSaw("高硬度锯片");
    }

    @Override
    public Chainsaws getChainsaws() {
        return chainsaws;
    }
}

同样的过了几天,光头强打电话给五金店老板。

HardwareStoreBoss hardwareStoreBoss = new HardwareStoreBoss();

五金店老板跟光头强说你等会儿,我先去问问链锯(这时候是:新链锯)做好了没,于是:

  Chainsaws chainsaws = hardwareStoreBoss.notify(new ChainsawBuilderImpl2());
        System.out.println(chainsaws.toString());

这时候打印结果是:

Chainsaws{
 battery='环保大容量锂电池', motor='动力强耐高温散热好的纯铜电机', reductionGearbox='减震变频高功率变速箱', hood='加厚加固耐磨抗打击防护罩', handle='人体工体学包胶手柄', switches='调速防误触智能开关', plug='环保防触电插头', circularSaw='高硬度锯片'链锯已经做好了
}

于是光头强就去拿到新链锯愉快的砍树去了。

(二)UML图解如下:


四、减少指挥者角色(光头强联系厂家定制)

(一)各个类的介绍:

光头强发现一个链锯不够用了,还想再买一个,但是每次通过五金店老板去询问太麻烦了,于是通过网上官网查询,找到了生产厂家的售后电话,直接联系他们,又重新定制了一个链锯。

厂家看光头强已经是第三次购买,算是VIP用户了,特意为他开了一个后门,车间有同意协调(链锯建造者类)专门管理。

/**
 * 链锯建筑者
 */
public interface ChainsawBuilder {

    // 蓄电池
    ChainsawBuilder battery(String name);
    // 电动机
    ChainsawBuilder motor(String name);
    // 减速箱
    ChainsawBuilder reductionGearbox(String name);
    // 防护罩
    ChainsawBuilder hood(String name);
    // 手柄
    ChainsawBuilder handle(String name);
    // 开关
    ChainsawBuilder switches(String name);
    // 插头
    ChainsawBuilder plug(String name);
    // 圆锯片
    ChainsawBuilder circularSaw(String name);

    // 获取链锯(产品)的实例
    Chainsaws getChainsaws();

}

这样一来,可以快速由专人负责找到对应的零件。

具体的生产建筑者这边也没闲着,也跟着做了改变,之前是规矩写死的,我这里有什么,客户才能定制什么(方法传入的String类型的参数),现在是可互需要的是什么,我这边就负责生产什么样的。具体如下:

/**
 * 链锯建筑者(具体建筑者)
 */
public class ChainsawBuilderImpl2 implements ChainsawBuilder {

    private Chainsaws chainsaws;

    public ChainsawBuilderImpl2() {
        chainsaws = new Chainsaws();
    }

    @Override
    public ChainsawBuilder battery(String name) {
        chainsaws.setBattery(name);
        return this;
    }

    @Override
    public ChainsawBuilder motor(String name) {
        chainsaws.setMotor(name);
        return this;
    }

    @Override
    public ChainsawBuilder reductionGearbox(String name) {
        chainsaws.setReductionGearbox(name);
        return this;
    }

    @Override
    public ChainsawBuilder hood(String name) {
        chainsaws.setHood(name);
        return this;
    }

    @Override
    public ChainsawBuilder handle(String name) {
        chainsaws.setHandle(name);
        return this;
    }

    @Override
    public ChainsawBuilder switches(String name) {
        chainsaws.setSwitches(name);
        return this;
    }

    @Override
    public ChainsawBuilder plug(String name) {
        chainsaws.setPlug(name);
        return this;
    }

    @Override
    public ChainsawBuilder circularSaw(String name) {
        chainsaws.setCircularSaw(name);
        return this;
    }

    @Override
    public Chainsaws getChainsaws() {
        return chainsaws;
    }
}

光头强这时候想问厂家做好了没,告诉厂家自己要做的零部件的类型,厂家就一次性安排生产了:

 ChainsawBuilderImpl2 chainsawBuilderImpl2 = new ChainsawBuilderImpl2();
Chainsaws chainsaws = chainsawBuilderImpl2.battery("环保大容量锂电池")
                .motor("动力强耐高温散热好的纯铜电机")
                .reductionGearbox("减震变频高功率变速箱")
                .hood("加厚加固耐磨抗打击防护罩")
                .handle("人体工体学包胶手柄")
                .switches("调速防误触智能开关")
                .plug("环保防触电插头")
                .circularSaw("高硬度锯片")
                .getChainsaws();

这时候打印结果还是一样的:

Chainsaws{
 battery='环保大容量锂电池', motor='动力强耐高温散热好的纯铜电机', reductionGearbox='减震变频高功率变速箱', hood='加厚加固耐磨抗打击防护罩', handle='人体工体学包胶手柄', switches='调速防误触智能开关', plug='环保防触电插头', circularSaw='高硬度锯片'链锯已经做好了
}

(二)UML图解如下:


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

推荐阅读更多精彩内容