3、创建型模式之建造者模式

建造者模式

建造者模式(Builder Pattern)使用多个简单的对象一步一步构建成一个复杂的对象。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

一个 Builder 类会一步一步构造最终的对象。该 Builder 类是独立于其他对象的。

介绍

意图:将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。

主要解决:主要解决在软件系统中,有时候面临着"一个复杂对象"的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。

何时使用:一些基本部件不会变,而其组合经常变化的时候。

如何解决:将变与不变分离开。

关键代码:建造者:创建和提供实例,导演:管理建造出来的实例的依赖关系。

应用实例: 1、去肯德基,汉堡、可乐、薯条、炸鸡翅等是不变的,而其组合是经常变化的,生成出所谓的"套餐"。 2、JAVA 中的 StringBuilder。

优点: 1、建造者独立,易扩展。 2、便于控制细节风险。

缺点: 1、产品必须有共同点,范围有限制。 2、如内部变化复杂,会有很多的建造类。

建造者模式包括的角色:
(1)Builder:给出一个抽象接口或抽象类,以规范产品的建造。这个接口规定要实现复杂对象的哪些部分的创建,并不涉及具体的对象部件的创建,一般由子类具体实现。
(2)ConcreteBuilder:Builder接口的实现类,并返回组建好对象实例。
(3)Director:调用具体建造者来创建复杂对象的各个部分,在指导者中不涉及具体产品的信息,只负责保证对象各部分完整创建或按某种顺序创建。
(4)Product:要创建的复杂对象,产品类。

建造者模式的使用场景:
(1)当产品有复杂的内部构造时(参数很多)。
(2)需要生产的产品的属性相互依赖,这些属性的赋值顺序比较重要时(因为在调用ConcreteBuilder的赋值方法时是有先后顺序的)。

注意事项:与工厂模式的区别是:建造者模式更加关注与零件装配的顺序。

案例一

下面是利用建造者模式“组装一台电脑”的实现方式,便于理解该模式如何运用。
1.产品类
要组装一台电脑(Computer类),我们假设它有三个部件:CPU 、主板以及内存。
在Computer类中提供三个set方法分别设置这三个属性。

public class Computer {  
    private String mCpu;  
    private String mMainboard;  
    private String mRam;  
  
    public void setmCpu(String mCpu) {  
        this.mCpu = mCpu;  
    }  
  
    public void setmMainboard(String mMainboard) {  
        this.mMainboard = mMainboard;  
    }  
  
    public void setmRam(String mRam) {  
        this.mRam = mRam;  
    }  
}  

2 .Builder类
下面就是一个抽象的Builder类,里面提供了安装CPU、主板和内存的抽象方法,以及组装成电脑的create方法。

public abstract class Builder {  
    public abstract void buildCpu(String cpu);  
    public abstract void buildMainboard(String mainboard);  
    public abstract void buildRam(String ram);  
    public abstract Computer create();  
}  

3. Builder实现类
下面是一个继承Builder的子类,里面不仅新建了Computer的实例,还提供了安装CPU、主板和内存的具体实现方法,并且在组装成电脑的create方法中将该Computer对象实例返回。

public class MyComputerBuilder extends Builder {  
    private Computer mComputer = new Computer();  
    @Override  
    public void buildCpu(String cpu) {  
        mComputer.setmCpu(cpu);  
    }  
  
    @Override  
    public void buildMainboard(String mainboard) {  
        mComputer.setmMainboard(mainboard);  
    }  
  
    @Override  
    public void buildRam(String ram) {  
        mComputer.setmRam(ram);  
    }  
  
    @Override  
    public Computer create() {  
        return mComputer;  
    }  
}  

4 .Director类
指挥者(Director)类用来规范组装电脑的流程顺序,先安装主板,再安装CPU,最后安装内存并组装成电脑。

public class Direcror {  
    Builder mBuild=null;  
    public Direcror(Builder build){  
        this.mBuild=build;  
    }  
    public Computer CreateComputer(String cpu,String mainboard,String ram){  
        //规范建造流程,这个顺序是由它定的  
       this.mBuild.buildMainboard(mainboard);  
       this.mBuild.buildCpu(cpu);  
       this.mBuild.buildRam(ram);  
       return mBuild.create();  
    }  
}  

5.使用

Builder mBuilder = new MyComputerBuilder();  
Direcror mDirecror=new Direcror(mBuilder);  
mDirecror.CreateComputer("i7","Intel主板","mRam");//返回Computer实例对象

以上便完成了整个建造者模式的实现细节。

建造者模式精简版
在现实开发中,往往省去Director的角色,而直接使用一个Buider实例来进行对象的组装。

建造者模式优缺点
建造者模式的优点:
(1)建造模式是将复杂的内部创建封装在内部,对于外部调用的人来说,只需要传入建造者和建造工具,对于内部是如何建造成成品的,调用者无需关心,良好的封装性是建造者模式的优点之一。
(2)建造者类逻辑独立,易拓展。
建造者模式的缺点:
很明显产生了多余的Build对象以及Dirextor对象,消耗了内存。

实例二

参与者

1.Builder
  为创建一个Product对象的各个部件指定抽象接口。
2.ConcreteBuilder
  实现Builder的接口以构造和装配该产品的各个部件。
  定义并明确它所创建的表示。
  提供一个检索产品的接口。
3.Director
  构造一个使用Builder接口的对象。
4.Product
  表示被构造的复杂对象。ConcreteBuilder创建该产品的内部表示并定义它的装配过程。
  包含定义组成部件的类,包括将这些部件装配成最终产品的接口。

类图

image.png

1.Builder

package com.nieshenkuan.creational.builderPattern.demo;

public interface PersonBuilder {

    void buildHead();

    void buildBody();

    void buildFoot();

    Person buildPerson();
    
}

2.ConcreteBuilder

package com.nieshenkuan.creational.builderPattern.demo;

public class ManBuilder implements PersonBuilder {

    Person person;

    public ManBuilder() {
        person = new Man();
    }

    public void buildBody() {
        person.setBody("建造男人的身体");
    }

    public void buildFoot() {
        person.setFoot("建造男人的脚");
    }

    public void buildHead() {
        person.setHead("建造男人的头");
    }

    public Person buildPerson() {
        return person;
    }
}

3.Director

package com.nieshenkuan.creational.builderPattern.demo;

public class PersonDirector {

    public Person constructPerson(PersonBuilder pb) {
        pb.buildHead();
        pb.buildBody();
        pb.buildFoot();
        return pb.buildPerson();
    }
}

4.Product

package com.nieshenkuan.creational.builderPattern.demo;

public class Person {

    private String head;

    private String body;

    private String foot;

    public String getHead() {
        return head;
    }

    public void setHead(String head) {
        this.head = head;
    }

    public String getBody() {
        return body;
    }

    public void setBody(String body) {
        this.body = body;
    }

    public String getFoot() {
        return foot;
    }

    public void setFoot(String foot) {
        this.foot = foot;
    }
}
package com.nieshenkuan.creational.builderPattern.demo;

public class Man extends Person{

}

5.Test

package com.nieshenkuan.creational.builderPattern.demo;

public class Test {
    public static void main(String[] args) {
        PersonDirector pd = new PersonDirector();
        Person person = pd.constructPerson(new ManBuilder());
        System.out.println(person.getBody());
        System.out.println(person.getFoot());
        System.out.println(person.getHead());
    }
}

结果:

建造男人的身体
建造男人的脚
建造男人的头

2018/04/25

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