设计模式之建造者模式
建造者模式又被称为生成器模式,感觉跟模板方法模式有点像,又和抽象工厂模式有点像,对于模板方法而言,它制造出来的子类大多数是一致的,而对于子类需求变化很大的部分,虽然模板方法通过钩子函数能解决,但是如果每个变化都调用一次钩子函数,那也不是个事儿。对于抽象工厂而言,建造者模式返回一个完整的复杂产品,而抽象工厂模式返回一系列相关的产品;在抽象工厂模式中,客户端通过选择具体工厂来生成所需对象,而在建造者模式中,客户端通过指定具体建造者类型并指导Director类如何去生成对象,侧重于一步步构造一个复杂对象,然后将结果返回。因此这些模式之间相互穿插,并不是各个完全独立开来,但是为了解决各种具体实际的问题,又各有变化。先来个建造者的UML图如下(当然又是我盗来的图):
Builder(抽象建造者):它为创建一个产品Product对象的各个部件指定抽象接口,里面的build方法用于创建复杂对象的各个部件,getResult用于返回复杂对象;
ConcreteBuilder(具体建造者):它实现了Builder接口,实现各个部件的具体构造和装配方法,定义并明确它所创建的复杂对象,也可以提供一个方法返回创建好的复杂产品对象。
Product(产品角色):它是被构建的复杂对象,包含多个组成部件,具体建造者创建该产品的内部表示并定义它的装配过程。
Director(指挥者):指挥者又称为导演类,它负责安排复杂对象的建造次序,它通过里面的construct方法调用建造者对象的部件构造与装配方法,完成复杂对象的建造。客户端一般与指挥者打交道就好了。
以上是对于建造者各个成员的作用的描述,下面还是通过小明蛋糕店来试试这个模式。话说小明的蛋糕店开的大了,招收了几个做蛋糕的师傅,可是师傅们指出蛋糕的制作步骤不一样,出来的口味也是不一样的,我们要针对不同客户做出不同的风味。可是根据之前的模板,步骤都是先成型然后涂抹最后烘烤,这样的模板就不能满足变化多的需求了。于是小明想到用一个ArrayList存放方法步骤,不同的风味就通过不同的存放顺序来完成。
abstract class Cake { private ArrayList<String> arr = new ArrayList<>(); protected abstract void shape(); protected abstract void apply(); protected abstract void braking(); final public void run() { for(int i=0;i<arr.size();i++){ if(arr.get(i)=="shape") { shape(); } else if(arr.get(i)=="apply") { apply(); } else if(arr.get(i)=="braking") { braking(); } } } final public void setArr(ArrayList<String> arrayList) { this.arr = arrayList; } }
main方法里测试了一下,发现这样子似乎是可行的
public static void main(String[] args) { CreamCake ccake = new CreamCake(); ArrayList<String> arr = new ArrayList<>(); arr.add("apply"); arr.add("shape"); arr.add("braking"); ccake.setArr(arr); ccake.run(); }
这样成功地调整了制作步骤,但是总不能我们没需要一种步骤的做法,就在main方法里弄一个列表,存放步骤吧,那也太麻烦,而且一点都不符合代码之道。对于这种变化频繁的东西,我们单独弄个类来管理它,先来个抽象的
abstract class CakeBuilder{ protected abstract void setArr(ArrayList<String> arr); protected abstract Cake getCake(); }
再以奶油蛋糕为例,来个奶油蛋糕的builder
class CreamCakeBuilder extends CakeBuilder { CreamCake cake = new CreamCake(); @Override protected void setArr(ArrayList<String> arr) { this.cake.setArr(arr); } @Override protected Cake getCake() { return cake; } }
看到这是不是感觉这很像一个抽象工厂和具体工厂啊,是的,非常相似!但是建造者方法重在组装零件,方法都已经实现了的,它负责搭配,而工厂方法负责的是生产零件,它不负责搭配。
现在再弄一个导演类来对付这些各类builder,还是以奶油蛋糕为例吧:
class Director { private ArrayList<String> arr = new ArrayList<>(); private CreamCakeBuilder cCakeBuilder = new CreamCakeBuilder(); public CreamCake getCreamCake() { this.arr.clear(); this.arr.add("apply"); this.arr.add("braking"); this.arr.add("shape"); this.cCakeBuilder.setArr(arr); return (CreamCake) cCakeBuilder.getCake(); } }
大致就是这样子,我始终觉得设计模式只是用于参考的东西,如果胡乱套用设计模式,收到的结果是相反的。