Java 设计模式——建造者模式(Builder Pattern)

image

前言

建造者模式又被称呼为生成器模式,这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
使用多个简单的对象一步一步构建成一个复杂的对象,有点像造房子一样一步步从地基做起到万丈高楼。我想这也是为什么被称呼为建造者模式的原因吧!反正我是找不出更好的理由了。这样理解反而更容易记住。不好意思,废话有点多了,且看下文如何分解!!!

一、简介

1、定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示
2、主要作用:在用户不知道对象的建造过程和细节的情况下就可以直接创建复杂的对象。
3、如何使用:用户只需要给出指定复杂对象的类型和内容,建造者模式负责按顺序创建复杂对象(把内部的建造过程和细节隐藏起来)
4、解决的问题
(1)、方便用户创建复杂的对象(不需要知道实现过程)
(2)、代码复用性 & 封装性(将对象构建过程和细节进行封装 & 复用)
5、注意事项:与工厂模式的区别是:建造者模式更加关注与零件装配的顺序,一般用来创建更为复杂的对象

哈哈! 本人比较懒,上面特性都是从其他博客中吸取到的精华,归纳与此,方便以后查阅。

image

二、实现方式

研究了好久发现关于建造者模式的实现例子有好多,有造人、造车、造房子、造世界的...等好多。但归类后有两种实现方式。

(1)通过Client、Director、Builder和Product形成的建造者模式

(2)通过静态内部类方式实现零件无序装配话构造

三、常见第一种方式

通过Client、Director、Builder和Product形成的建造者模式

(1)一般有以下几个角色

抽象建造者(builder):描述具体建造者的公共接口,一般用来定义建造细节的方法,并不涉及具体的对象部件的创建。

具体建造者(ConcreteBuilder):描述具体建造者,并实现抽象建造者公共接口。

指挥者(Director):调用具体建造者来创建复杂对象(产品)的各个部分,并按照一定顺序(流程)来建造复杂对象。

产品(Product):描述一个由一系列部件组成较为复杂的对象。

(2)举个例子

既然是建造者模式,那么我们还是继续造房吧,其实我也想不到更简单的例子。

假设造房简化为如下步骤:(1)地基(2)钢筋工程(3)铺电线(4)粉刷

“如果”要盖一座房子,首先要找一个建筑公司或工程承包商(指挥者)。承包商指挥工人(具体建造者)过来造房子(产品),最后验收。

(3)具体步骤

1、创建抽象建造者定义造房步骤

2、创建工人具体实现造房步骤

3、创建承包商指挥工人施工

4、验收,检查是否建造完成

好了,到这里第一种方法就讲解完了。具体步骤都给了,大家可以尝试写一下,写不出来没关系。
——大家可以复制啊!省时间嘛,但不写的话更容易忘记。好了广告打完了,到贴代码时间...

image

(4)具体代码

建造者:Builder.java

/**
 * Builder.java
 *  建造者
 */
abstract class Builder {
    //地基
    abstract void bulidA();
    //钢筋工程
    abstract void bulidB();
    //铺电线
    abstract void bulidC();
    //粉刷
    abstract void bulidD();
    //完工-获取产品
    abstract Product getProduct();
}
image.gif

产品:Product.java

/**
 * Product.java
 *  产品(房子)
 */
public class Product {
    private String buildA;
    private String buildB;
    private String buildC;
    private String buildD;
    public String getBuildA() {
        return buildA;
    }
    public void setBuildA(String buildA) {
        this.buildA = buildA;
    }
    public String getBuildB() {
        return buildB;
    }
    public void setBuildB(String buildB) {
        this.buildB = buildB;
    }
    public String getBuildC() {
        return buildC;
    }
    public void setBuildC(String buildC) {
        this.buildC = buildC;
    }
    public String getBuildD() {
        return buildD;
    }
    public void setBuildD(String buildD) {
        this.buildD = buildD;
    }
    @Override
        public String toString() {
            return buildA+"\n"+buildB+"\n"+buildC+"\n"+buildD+"\n"+"房子验收完成";
        }
}
image.gif

具体建造者:ConcreteBuilder.java

/**
 * ConcreteBuilder.java
 *  具体建造者(工人)
 */
public class ConcreteBuilder extends Builder{
    private Product product;
    public ConcreteBuilder() {
        product = new Product();
    }
    @Override
    void bulidA() {
        product.setBuildA("地基");
    }
    @Override
    void bulidB() {
        product.setBuildB("钢筋工程");
    }
    @Override
    void bulidC() {
        product.setBuildC("铺电线");
    }
    @Override
    void bulidD() {
        product.setBuildD("粉刷");
    }
    @Override
    Product getProduct() {
        return product;
    }
}
image.gif

指挥者:Director.java

/**
 * Director.java
 *  指挥者
 */
public class Director {
    //指挥工人按顺序造房
    public Product create(Builder builder) {
        builder.bulidA();
        builder.bulidB();
        builder.bulidC();
        builder.bulidD();
        return builder.getProduct();
    }
}
image.gif

测试类:Test.java

/**
 * Test.java
 *  测试类
 */
public class Test {
    public static void main(String[] args) {
        Director director = new Director();
        Product create = director.create(new ConcreteBuilder());
        System.out.println(create.toString());
    }
}
image.gif
image

代码贴完了,有没有感觉,看代码比看文字好多了。嗯嗯 我也是这么觉得 可惜不能光贴代码。不然我一天可以写10篇了T-T。

三、第二种方式

通过静态内部类方式实现零件无序装配话构造:案例:Android中的AlertDialog

这种方式使用更加灵活,更符合定义。内部有复杂对象的默认实现,使用时可以根据用户需求自由定义更改内容,并且无需改变具体的构造方式。就可以生产出不同复杂产品

(1)主要有三个角色:抽象建造者、具体建造者、产品

比第一种方式少了指挥者,主要是因为第二种方式把指挥者交给用户来操作,使得产品的创建更加简单灵活。

(2)举个例子

比如麦当劳的套餐,服务员(具体建造者)可以随意搭配任意几种产品(零件)组成一款套餐(产品),然后出售给客户。

(3)具体步骤

1、创建建造者定义麦当劳的产品

2、创建服务员实现具体产品

3、服务员随意搭配套餐出售给客户

(4)具体代码

建造者:Builder.java

/**
 * Builder.java
 *  建造者
 */
abstract class Builder {
    //汉堡
    abstract Builder bulidA(String mes);
    //饮料
    abstract Builder bulidB(String mes);
    //薯条
    abstract Builder bulidC(String mes);
    //甜品
    abstract Builder bulidD(String mes);
    //获取套餐
    abstract Product build();
}
image.gif

产品:Product.java

/**
 * Product.java
 *  产品(麦当劳套餐)
 */
public class Product {
    private String buildA="汉堡";
    private String buildB="饮料";
    private String buildC="薯条";
    private String buildD="甜品";
    public String getBuildA() {
        return buildA;
    }
    public void setBuildA(String buildA) {
        this.buildA = buildA;
    }
    public String getBuildB() {
        return buildB;
    }
    public void setBuildB(String buildB) {
        this.buildB = buildB;
    }
    public String getBuildC() {
        return buildC;
    }
    public void setBuildC(String buildC) {
        this.buildC = buildC;
    }
    public String getBuildD() {
        return buildD;
    }
    public void setBuildD(String buildD) {
        this.buildD = buildD;
    }
    @Override
        public String toString() {
            return buildA+"\n"+buildB+"\n"+buildC+"\n"+buildD+"\n"+"组成套餐";
        }
}
image.gif

具体建造者:ConcreteBuilder.java

/**
 * ConcreteBuilder.java
 *  具体建造者(服务员)
 */
public class ConcreteBuilder extends Builder{
    private Product product;
    public ConcreteBuilder() {
        product = new Product();
    }

    @Override
    Product build() {
        return product;
    }

    @Override
    Builder bulidA(String mes) {
        product.setBuildA(mes);
        return this;
    }

    @Override
    Builder bulidB(String mes) {
        product.setBuildB(mes);
        return this;
    }

    @Override
    Builder bulidC(String mes) {
        product.setBuildC(mes);
        return this;
    }

    @Override
    Builder bulidD(String mes) {
        product.setBuildD(mes);
        return this;
    }
}
image.gif

测试类:Test.java

/**
 * Test.java
 *  测试类
 */
public class Test {
    public static void main(String[] args) {
         ConcreteBuilder concreteBuilder = new ConcreteBuilder();
         Product build = concreteBuilder
                .bulidA("牛肉煲")
//              .bulidC("全家桶")
                .bulidD("冰淇淋")
                .build();
        System.out.println(build.toString());
    }
}
image.gif
image

突然发现贴代码也是一个技术活,一不小心就贴了一晚上。唉唉唉,又熬夜了啊,我可怜的头发

image

四、总结

(1)优点

1、产品的建造和表示分离,实现了解耦。

2、将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰

3、增加新的具体建造者无需修改原有类库的代码,易于拓展,符合“开闭原则“。

(2)缺点

1、产品必须有共同点,限制了使用范围。

2、如内部变化复杂,会有很多的建造类,难以维护。

(3)应用场景

1、需要生成的产品对象有复杂的内部结构,这些产品对象具备共性;

2、隔离复杂对象的创建和使用,并使得相同的创建过程可以创建不同的产品。

3、需要生成的对象内部属性本身相互依赖。

4、适合于一个具有较多的零件(属性)的产品(对象)的创建过程。

五、Demo地址

https://github.com/DayorNight/DesignPattern

六、参考文档

https://www.jianshu.com/p/be290ccea05a

http://www.runoob.com/design-pattern/builder-pattern.html

https://www.cnblogs.com/lwbqqyumidi/p/3742562.html

七、内容推荐

简书:https://blog.csdn.net/cs_lwb/article/details/84261641

相关文章:

《JAVA 设计模式——单例模式》

《Java 设计模式——工厂模式》

《Java 设计模式——观察者模式》

如果你觉得我写的不错或者对您有所帮助的话。不妨顶一个(点个赞呗),也方便以后复习

您的每个举动都是对我莫大的支持

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

推荐阅读更多精彩内容