Builder 模式

来源:互联网 发布:二阶矩阵特征值的求法 编辑:程序博客网 时间:2024/09/21 09:25

问题背景

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

设计一

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

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();    }}
0 0
原创粉丝点击