Builder 模式

问题背景

你要建造一所房子。大兴土木当然应该用很多劳力,但是知识分子也是必要的——要不房子结构会出问题,或者很难看。你需要一个设计师,这个人呢,知道怎么建房子。这个人会告诉你,建房子啊,应该先从底下开始(神说地基已经打好了),你得先弄弄地板,再弄弄墙,再在墙上打几个洞,一些当窗户,弄个接地气的当门。

设计一

所以我们有了一个无脑的设计。

class House {

    private void buildFloor() {
        //
    }

    private void buildWall() {
        //
    }

    private void buildWindows() {
        //
    }

    private void buildDoor() {
        //
    }

    public House() {
        buildFloor();
        buildWall();
        buildWindows();
        buildDoor();
    }
}

不过其实也不是非常无脑,起码你没把四个 build* 函数的东西一股脑都填到构造函数里。

设计一的问题

那么这个设计怎么样呢?直接看起来好像还好。

可是天要亡你。用户改需求啦!用户说,我有 100 套房子(壕),怎么能都建成一样的呢?我要这几套建成中式(China)的,这几套建成罗马式(Rome)的,那几套……

设计师一听就头大了,这样一想原来的设计的确有问题:它的扩展性太差。不能支持“房子”的多样性。

出现这种状况的原因是什么呢?我们看一看这个类有什么功能。第一、它建立了房子的各个部分;第二、它将各个部分组合起来。

如果是一个简单一点的类的话,这样写其实没有多大问题,类有几个部分的话自然就应该这么构造。可是房子这个类比较复杂,它的种类太多也就是第一个功能部分要求扩展性;同时又有比较固定的构成,有了地板、墙壁、门等的构造方法之后,不论他们是什么风格的,组合起来的逻辑都是一样的。

也就是说,房子这个类具有两个特性:

  1. 成分多样性高。
  2. 各个成分直接组成逻辑固定。

对应着两项特性,构造房子这个工作,是由两个特征鲜明的部分组成:构建各个成分设计组装。在一个类中完成两项工作是不合适的,所以我们将把两个部分分开来做。

Builder 模式

首先我们来弄一个 Builder 类,用这个类做构建各个部分这件事情。

package builder;

import house.House;

public class Builder {

    House house = new House();

    public void buildFloor();

    public void buildWall();

    public void buildWindows();

    public void buildDoor();

    public House getHouse();
}

类里的 getHouse(): void 就是得到最终房子的方法。请注意,这个 Builer 只是“民工”,它不懂设计,只知道每一部分怎么弄。

“民工”需要一个设计师来指挥,设计师就是完成第二件事,设计组装的人。

package designer;

import builder.Builder;

/**
 * @author plus7wist
 *
 */
public class Designer {

    public void concreteHouse(Builder builder) {
        builder.buildFloor();
        builder.buildWall();
        builder.buildDoor();
        builder.buildWindows();
    }
}

代码里很明显可以看出,设计师其实什么都不干,它只是指挥 builder 进行工作,它的指挥体现出了设计的逻辑,而这一点 builder 又是不必操心的。

这种两者合作的结构就是典型的 Builder 模式。

扩展性

我们再看看这个设计进行扩展的时候会怎么样。无论风格怎么改变,Designer 的逻辑都不变。对于多样变化的 Builder 我们很容易想到一种解决办法:利用多态,将原来的 Builder 变成抽象的。

package builder;

import house.House;

public abstract class Builder {

    public abstract void buildFloor();

    public abstract void buildWall();

    public abstract void buildWindows();

    public abstract void buildDoor();

    public abstract House getHouse();
}

为了表示方便我们简要的写一下 House。用一个数组把成分的样子存起来。

package house;

import java.util.ArrayList;

public class House {
    private ArrayList<String> parts = new ArrayList<String>();

    public void add(String part) {
        parts.add(part);
    }

    public void display() {
        for (int i = 0; i < parts.size(); ++i)
            System.out.print((i == 0 ? "" : ",") + parts.get(i));
        System.out.println();
    }
}

然后如果建中国风格的房子的话,就建一个ChinaHouseBuilder,继承自 Builder

package concrete.builder;

import house.House;
import builder.Builder;

/**
 * @author plus7wist
 *
 */
public class ChinaHouseBuilder extends Builder {

    House chinaHouse = new House();

    @Override
    public void buildFloor() {
        chinaHouse.add("China Floor");
    }

    @Override
    public void buildWall() {
        chinaHouse.add("China Wall");
    }

    @Override
    public void buildWindows() {
        chinaHouse.add("China Windows");
    }

    @Override
    public void buildDoor() {
        chinaHouse.add("China Door");
    }

    @Override
    public House getHouse() {
        return chinaHouse;
    }
}

如果建罗马风格的房子的话,就建一个RomeHouseBuilder

package concrete.builder;

import house.House;
import builder.Builder;

/**
 * @author plus7wist
 *
 */
public class RomeHouseBuilder extends Builder {

    House romeHouse = new House();

    @Override
    public void buildFloor() {
        romeHouse.add("Rome Floor");
    }

    @Override
    public void buildWall() {
        romeHouse.add("Rome Wall");
    }

    @Override
    public void buildWindows() {
        romeHouse.add("Rome Windows");
    }

    @Override
    public void buildDoor() {
        romeHouse.add("Rome Door");
    }

    @Override
    public House getHouse() {
        return romeHouse;
    }
}

如此一来,我们发现 Designer 的逻辑完全不用改——当真是个好的设计。

最后我们看一眼怎么使用这个东西。

package main;

import builder.Builder;
import house.House;
import concrete.builder.*;
import designer.Designer;

/**
 * @author plus7wist
 *
 */
public class Main {

    /**
     * @param args
     */
    public static void main(String[] args) {
        Builder chinaHouseBuilder = new ChinaHouseBuilder();
        Builder romeHouseBuilder = new RomeHouseBuilder();
        Designer designer = new Designer();
        designer.concreteHouse(chinaHouseBuilder);
        designer.concreteHouse(romeHouseBuilder);
        House chinaHouse = chinaHouseBuilder.getHouse();
        House romeHouse = romeHouseBuilder.getHouse();
        chinaHouse.display();
        romeHouse.display();
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值