建造者模式(Builder Pattern)
LanyuanXiaoyao's Blog ヽ(✿゚▽゚)ノ

建造者模式(Builder Pattern)


简介

建造者模式,是一种对象构建模式。它可以将复杂对象的建造过程抽象出来(抽象类别),使这个抽象过程的不同实现方法可以构造出不同表现(属性)的对象。

建造者模式又被称为生成器模式,建造模式等,实际上建造者模式的核心就在于把对象的构造过程抽象出来。
让我们举个例子,比如我们常常在电视上看到做菜的节目,做一道菜出来,必须是要经过洗菜,炒菜,放盐,放调料……吧啦吧啦一套程序下来,才能变成我们吃的美味的菜,但是轮到我们自己做的时候,可能就已经不是很记得清步骤了,到底是要先放盐呢还是要先加水呢?这个时候我们就会想到把这个做菜的步骤记录下来,然后自己就可以一步一步按照步骤来做菜了,也许在细致一点,我们还可以把放多少盐加多少水都记下来,这样我们自己做的菜就和电视里面的菜相差无几了。
其实这个例子,就是建造者模式的来由,很多时候我们要构建很多相同的组件,但是组件的内部构造很多很复杂,所以这个时候我们就有需要一张构建这个组件的“菜谱”,只要按照这上面的步骤来做,就不会出问题。而且,当我们需要不同的表现的时候,也可以轻易地更改其中的设置,因为我们对其中某个步骤的更改并不会影响我们组件的正常生成。比如我们的菜是给广东人吃,就少放点盐,比如我们的菜给东北人吃,就多放点辣椒,但是口味虽然不同,但是绝对不会把这个菜做坏,因为所有要加的东西我们的按照步骤加好了。

适用情况

让我们把情况说得专业一点

  1. 需要生成的产品对象有复杂的内部结构,这些产品对象通常包含多个成员属性。
  2. 需要生成的产品对象的属性相互依赖,需要指定其生成顺序
  3. 对象的创建过程独立于创建该对象的类。在建造者模式中引入了指挥者类,将创建过程封装在指挥者类中,而不在建造者类中。
  4. 隔离复杂对象的创建和使用,并使得相同的创建过程可以创建不同的产品

简单来说,就是我们需要构造很多个构造流程相同或相似的很多组件的时候,就把这个构造过程抽象出来,而且由于组件的内部组成复杂,流程较多,我们需要一个东西来帮我们把控这个构建过程

特点

构造者模式常常被用来构建组合结构的组件,这些组件的内部构造顺序和步骤比较稳定

优点

  • 在建造者模式中, 客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象,这相当于把复杂对象的构造过程封装起来了。
  • 每一个具体建造者都相对独立,而与其他的具体建造者无关,因此可以很方便地替换具体建造者或增加新的具体建造者, 用户使用不同的具体建造者即可得到不同的产品对象
  • 可以更加精细地控制产品的创建过程 。将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰,也更方便使用程序来控制创建过程。
  • 增加新的具体建造者无须修改原有类库的代码,指挥者类针对抽象建造者类编程,系统扩展方便,符合“开闭原则”。

    缺点

  • 建造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,则不适合使用建造者模式,因此其使用范围受到一定的限制。
  • 如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大。

代码

让我来实现一个简单的建造者模式,还是拿我们炒菜的例子,首先我们有一个lunch的类来表示我们的午饭

package builder;

/**
 * @author Lanyuanxiaoyao
 * @create 2017-07-22
 */

public class Lunch {

    // 用这个String来表示我们菜当前的样子
    private String lunchComposition;

    Lunch(String lunchName) {
        lunchComposition = lunchName;
    }

    public String getLunchComposition() {
        return lunchComposition;
    }

    public void setLunchComposition(String lunchComposition) {
        this.lunchComposition = lunchComposition;
    }
}

然后是一张“菜谱”,我们“菜谱”中做菜的过程已经被我们确定下来,但是具体的细节交给我们的子类去做

package builder;

public abstract class LunchBuilder {

    public Lunch lunch;

    LunchBuilder() {
        this.lunch = new Lunch("lunch");
    }

    abstract void addSalt();

    abstract void addWater();

    // 这里定义了构建过程,但是具体细节留给子类实现
    final public Lunch cook() {
        addSalt();
        addWater();
        return lunch;
    }

}

然后我是广东人,所以我要加少点盐和加多点水,这样味道会淡点,不那么重口味,于是建立了广东LunchBuilder

package builder;

/**
 * @author Lanyuanxiaoyao
 * @create 2017-07-22
 */

public class CantoneseLunchBuilder extends LunchBuilder {

    @Override
    void addSalt() {
        lunch.setLunchComposition(lunch.getLunchComposition() + " add少点Salt");
    }

    @Override
    void addWater() {
        lunch.setLunchComposition(lunch.getLunchComposition() + " add多点Water");
    }

}

然后就是开始做菜咯

package builder;

/**
 * @author Lanyuanxiaoyao
 * @create 2017-07-22
 */

public class LunchBuilderTest {

    public static void main(String[] args) {
        Lunch lunch = new CantoneseLunchBuilder().cook();
        System.out.println(lunch.getLunchComposition());
    }

}

运行结果:

可以看到我的菜炒成功了

简单分析

虽然这个我自制的例子很短,但是我感觉已经把建造者模式的意思表达出来了,首先是我们的LunchBuilder,这个类就是我们的总菜谱,定义了这个菜的做法是先要加盐,再加水,但是要加多少盐,加多少水呢?留给子类广东LunchBuilder去头疼这件事,最后我们我们不管加多少盐多少水,总是先加盐后加水,这样我们做的这个才就不会失误。

总结

建造者模式其实核心在于复用过程和抽象过程,在我们的建造过程非常复杂的情况下,比如要引入几十个类,这些类还互相依赖,这样我们肯定是不可能每次都去写一遍构造过程的,所以自然而然我们就要封装这个过程,达到省时省力的效果。


评论