嘻哈说:设计模式之建造者模式

栏目: 后端 · 发布时间: 6年前

内容简介:首先,请您欣赏闲来无事听听曲,知识已填脑中去;

首先,请您欣赏 建造者模式的原创歌曲

嘻哈说:建造者模式
作曲:懒人
作词:懒人
Rapper:懒人

将一个复杂对象的构建与它的表示分离
使得同样构建过程可以创建不同的表示
真是一步一步创建一个复杂对象的过程好似绅士
我在绞尽脑汁想着怎么包饺子
先皮再陷的构建过程不会存在猫腻
但皮和陷各有不同需要各位老师傅
我就是导演者,负责构建的整个过程
老师傅呢,是具体建造者,建造每个部件干活不磨蹭
饺子是产品角色,由一系列部件组成,不陌生
对了,记得还有抽象建造者
这样才能说声建造者模式可用
或者产品类中有个静态内部类Builder
这种方式算是折中
复制代码

试听请点击这里

闲来无事听听曲,知识已填脑中去;

学习复习新方式,头戴耳机不小觑。

番茄课堂,学习也要酷。

2、定义

无论是在现实世界中还是在软件系统中,都存在一些复杂的对象,它们拥有多个组成部分,如电脑,它包括CPU、硬盘、内存等各种部件。

对于大多数用户而言,无须知道这些部件的装配细节,也几乎不会使用单独某个部件,而是完整的一台电脑。

由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法确相对稳定。如何应对这种变化?

如何提供一种“封装机制”来隔离出“复杂对象的各个部分”的变化,从而保持系统中的 “稳定构建算法”不随着需求改变而改变?

这就是要说的建造者模式。

使用建造者模式,用户只需要指定复杂对象的类型就可以得到该对象,而无须知道其内部的具体构造细节。

我们来看一下建造者模式的定义。

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

怎么理解呢?

首先,是一个复杂的对象,并且将它的构造和表示分开。

这样做的目的是可以单独管理构建的过程,避免了调用者关心创建对象内部的逻辑或者顺序。

而且还可以用一样的构造过程创建不同的表示。

它既然是用来创建对象,那肯定就是 创建型模式

3、场景

美食饺子

番茄餐厅的后厨。

厨师长:最近有不少客户反馈,咱们的饺子上菜速度比较慢。我呢,重新规划了一下流程,首先擀饺子皮,然后绞饺子馅,最后搞熟。

厨师A:好的。

厨师长:你们不用管这个流程,我来负责流程。你们就负责擀饺子皮,绞饺子馅,还有搞熟。我让你们做哪步就做哪步。明白没?

厨师A:明白了。

厨师长:明白了还不赶紧干活去,这一天天的,什么时候能像我一样,求生欲这么强,咱们上菜速度就上去了。

4、建造者模式

嘻哈说:设计模式之建造者模式

建造者模式的UML类图。

package com.fanqiekt.builder;

/**
 * 饺子
 *
 * @Author: 番茄课堂-懒人
 */
public class Dumpling {
    private String wrapper; //饺子皮
    private String stuffing; //饺子馅

    public String getWrapper() {
        return wrapper;
    }

    public void setWrapper(String wrapper) {
        this.wrapper = wrapper;
    }

    public String getStuffing() {
        return stuffing;
    }

    public void setStuffing(String stuffing) {
        this.stuffing = stuffing;
    }

    @Override
    public String toString() {
        return "饺子皮是" + wrapper + ",饺子馅是" + stuffing;
    }
}
复制代码

Dumpling:它是产品(Product)角色,由一系列部件组成。

一般是一个较为复杂的对象,也就是说创建对象的过程比较复杂,一般会有比较多的代码量。

在本类图中,产品类是一个具体的类,而非抽象类。

实际编程中,产品类可以是由一个抽象类与它的不同实现组成,也可以是由多个抽象类与他们的实现组成。

package com.fanqiekt.builder;

/**
 * 抽象的Builder类
 *
 * @Author: 番茄课堂-懒人
 */
public interface Builder {
    // 饺子皮
    void buildWrapper(String wrapper);
    // 饺子馅
    void buildStuffing(String stuffing);
    // 创建Dumpling
    Dumpling build();
}
复制代码

Builder:它是抽象建造者(Builder)角色,给出一个抽象接口,以规范产品对象的各个组成成分的建造。

一般而言,此接口独立于应用程序的业务逻辑。

模式中直接创建产品对象的是具体建造者 (ConcreteBuilder)角色。

一般来说,产品所包含的零件数目与建造方法的数目相符。换言之,有多少零件,就有多少相应的建造方法。

引入抽象建造者的目的,是为了将建造的具体过程交与它的子类来实现,方便扩展其他的建造方式。

package com.fanqiekt.builder;

/**
 * 具体的 Builder类, 水饺的Builder
 *
 * @Author: 番茄课堂-懒人
 */
public class DumplingBuilder implements Builder{
    private Dumpling dumpling = new Dumpling();

    @Override
    public void buildWrapper(String wrapper) {
        System.out.println("制作饺子皮:" + wrapper);
        dumpling.setWrapper(wrapper);
    }

    @Override
    public void buildStuffing(String stuffing) {
        System.out.println("制作饺子陷:" + stuffing);
        dumpling.setStuffing(stuffing);
    }

    @Override
    public Dumpling build() {
        System.out.println("下过煮饺子");
        return dumpling;
    }
}
复制代码

DumplingBuilder:它是具体建造者(ConcreteBuilder)角色。

实现抽象类的所有未实现的方法,具体来说一般是两项任务:组建产品;返回组建好的产品。

它就相当于场景中的厨师A。

package com.fanqiekt.builder;

/**
 * 导演者
 *
 * @Author: 番茄课堂-懒人
 */
public class Director {
    Builder builder;

    public Director(Builder builder){
        this.builder = builder;
    }

    public void constructDumpling(String wrapper, String stuffing){
        builder.buildWrapper(wrapper);
        builder.buildStuffing(stuffing);
    }
}
复制代码

Director:它是导演者(Director)角色,负责调用适当的建造者来组建产品。

导演类一般不与产品类发生依赖关系,与导演类直接交互的是建造者类。

一般来说,导演类被用来封装程序中易变、及其复杂的部分。

package com.fanqiekt.builder;

/**
 * 客户端
 *
 * @Author: 番茄课堂-懒人
 */
public class Client {
    public static void main(String args[]){
        Builder builder = new DumplingBuilder();
        Director director = new Director(builder);
        director.constructDumpling("白面饺子皮", "猪肉大葱馅");
        Dumpling dumpling = builder.build();
        System.out.println("饺子出锅喽:" + dumpling.toString());
    }
}

复制代码

导演者角色是与客户端打交道的角色。

导演者将客户端创建产品的请求划分为对各个零件的建造请求,再将这些请求委派给具体建造者角色。

具体建造者角色是做具体建造工作的,但是却不为客户端所知。

在实际应用中,很多会把该角色省略。

他就相当于场景中求生欲极强的厨师长。

我们可以运行下,看一下结果。

制作饺子皮:白面饺子皮
制作饺子陷:猪肉大葱馅
下过煮饺子
饺子出锅喽:饺子皮是白面饺子皮,饺子馅是猪肉大葱馅

复制代码

如果我现在不止想做水饺,我还想做个蒸饺怎么办?

很简单,直接创建个新的Builder。

package com.fanqiekt.builder;

/**
 * 具体的 Builder类, 蒸饺的Builder
 *
 * @Author: 番茄课堂-懒人
 */
public class SteamedDumplingBuilder implements Builder{
    private Dumpling dumpling = new Dumpling();

    @Override
    public void buildWrapper(String wrapper) {
        System.out.println("制作饺子皮:" + wrapper);
        dumpling.setWrapper(wrapper);
    }

    @Override
    public void buildStuffing(String stuffing) {
        System.out.println("制作饺子陷:" + stuffing);
        dumpling.setStuffing(stuffing);
    }

    @Override
    public Dumpling build() {
        System.out.println("放在蒸笼上蒸饺子");
        return dumpling;
    }
}
复制代码

这就是抽象建造者的作用了。

5、建造者模式变种

您是不是感觉建造者角色太多,太麻烦了?

这个时候,我们建造者的变种就该登台亮相了。

嘻哈说:设计模式之建造者模式

建造者模式变种的UML类图。

package com.fanqiekt.builder.varietas;

/**
 * 饺子
 *
 * @Author: 番茄课堂-懒人
 */
public class Dumpling {
    Params params = new Params();

    private Dumpling(){
    }

    private String getWrapper() {
        return params.wrapper;
    }

    public String getStuffing() {
        return params.stuffing;
    }

    @Override
    public String toString() {
        return "饺子皮是" + getWrapper() + ",饺子馅是" + getStuffing();
    }

    /**
     * 静态内部类 Builder
     */
    public static class Builder {
        Params params = new Params();

        public Builder setWrapper(String wrapper) {
            params.wrapper = wrapper;
            return this;
        }

        public Builder setStuffing(String stuffing) {
            params.stuffing = stuffing;
            return this;
        }

        public Dumpling build() {
            Dumpling dumpling = new Dumpling();
            params.apply(dumpling.params);
            System.out.println("下过煮饺子");
            return dumpling;
        }
    }

    private static class Params {
        private String wrapper; //饺子皮
        private String stuffing; //饺子馅

        private void apply(Params params){
            System.out.println("制作饺子皮:" + wrapper);
            params.wrapper = wrapper;
            System.out.println("制作饺子陷:" + stuffing);
            params.stuffing = stuffing;
        }
    }
}
复制代码

在变种当中,抽象建造者角色没有了,导演者角色没有了,只剩下产品角色和具体建造者角色了。

具体建造者变成了产品的私有静态内部类。

增加了Params静态内部类,它是用来封装用到的属性的。

为什么要专门封装这么一个类呢?

如果没有的话,则Dumpling会拥有wrapper、stuffing属性。Builder中也要拥有wrapper、stuffing属性。

为了属性的统一性,就增加了Params静态内部类。

6、用途

建造者模式是一步一步创建一个复杂的对象,它允许用户只通过指定复杂对象的类型和内容就可以构建它们,用户不需要知道内部的具体构建细节。

所以,它的作用主要体现在两方面:复杂对象的构建、忽略具体的构建细节。

大概用途是:

(1)遇到多个构造器参数时。

(2)相同的方法,不同的执行顺序,产生不同的事件结果时。

(3)需要生成的产品对象的属性相互依赖,建造者模式可以强迫生成顺序。

7、优点

良好的封装性。

使用建造者模式可以使客户端不必知道产品内部的组成细节。

良好的扩展性。

增加新的具体建造者无须修改原有类库的代码,指挥者类针对抽象建造者类编程,系统扩展方便。

更加精细化。

可以更加精细地控制产品的创建过程。将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰,也更方便使用程序来控制创建过程。

创建不同的产品

将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象。

用户使用不同的具体建造者即可得到不同的产品对象。

8、缺点

系统庞大。

如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大。

使用局限性。

建造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,则不适合使用建造者模式,因此其使用范围受到一定的限制。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Artificial Intelligence

Artificial Intelligence

Stuart Russell、Peter Norvig / Pearson / 2009-12-11 / USD 195.00

The long-anticipated revision of this #1 selling book offers the most comprehensive, state of the art introduction to the theory and practice of artificial intelligence for modern applications. Intell......一起来看看 《Artificial Intelligence》 这本书的介绍吧!

MD5 加密
MD5 加密

MD5 加密工具

SHA 加密
SHA 加密

SHA 加密工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具