Builder建造者模式
建造者模式:是将一个复杂对象的创建与它的表像分离,使得同样的构建过程可以创建不同的表示。
我们首先理解一下建造者模式:根据他的定义,先拿人穿衣服来解释:
我们先理解第二句话“同样的构建过程”是指对象的创建有一个固定的过程,好比穿衣服,必须是先穿内衣,然后穿外衣,然后穿袜子,然后是鞋,过程是不变的。(不要跟我提内裤后穿的例子—超人,那种不适合建造者模式。也不要想先穿鞋后穿裤子或者衣服,那样太非主流也不舒服。)
就是在这种“同样的构建过程”中,男人或者女人们穿出了不同风格的衣服,展示了不同个性的区别。
所以:建造者模式使用的前提是对象创建过程或者流程要相同,也就是很固定。
第一句“一个复杂的对象”,这里如果用穿衣服来比喻,就是各种风格的衣服,如西装、休闲服、运动装等等,衣服风格非常多,很繁杂。
“对象创建与它的表象分离”,说明你看到衣服的风格与穿衣服的过程是分开的。
用穿衣服总结:将穿衣服的过程与看到衣服的款式分离,使得同样的穿衣过程可以穿出不同风格的衣服。
类图:
代码:
//抽象接口 -- 穿衣服 public abstract class Wear { // 抽象方法 -- 穿上衣 public abstract void coat(); // 抽象方法 -- 穿裤子 public abstract void pants(); // 抽象方法 -- 穿袜子 public abstract void socks(); // 抽象方法 -- 穿鞋子 public abstract void shoes(); // 形象展示 public void show(){ System.out.println("\n我今天的装扮是:"); this.coat(); this.pants(); this.socks(); this.shoes(); } }
/** * 西装的打扮 */ public class Suit extends Wear { public void coat() { System.out.print("上衣是西服"); } public void pants() { System.out.print(",下身是西裤"); } public void shoes() { System.out.print(",黑色的袜子"); } public void socks() { System.out.print(",黑色的皮鞋!"); } }
/** * 运动装的打扮 */ public class SportsWear extends Wear{ public void coat() { System.out.print("上身是运动服"); } public void pants() { System.out.print(",下身是运动裤!"); } public void socks() { System.out.print(",白色的袜子!"); } public void shoes() { System.out.print(",白色的运动鞋"); } }
/** * 指挥者 -- 张三 * 根据自己的想法穿不同风格的衣服 */ public class JoeSmith { // 穿衣服 private Wear wear; // 给人的感觉 public void feel(){ wear.show(); } /** * 张三的构造方法,必须穿衣服 **/ public JoeSmith(Wear wear) { this.wear = wear; } // getter && setter public Wear getWear() { return wear; } public void setWear(Wear wear) { this.wear = wear; } }
public class Client { public static void main(String[] args) { // 今天上班,穿西装 Wear wear = new Suit(); JoeSmith js = new JoeSmith(wear); js.feel(); // 下班了,去健身房,换套运动装 js.setWear( new SportsWear()); js.feel(); } }
张三作为管理这,有一个构建各种风格衣服的穿衣服的建造者类,而具体的建造者是各种风格迥异的衣服,张三穿衣服出门,并且展示自己穿的一身衣服本来是一体化的,而建造者模式就是将张三在选择穿什么款式衣服出门的时候,将穿衣服的过程与最后的形象分离开了,解决了张三穿其它款式衣服时,又去建立一个穿衣流程的繁琐。
这里重点是将穿衣的过程和看到的款式进行分离。
下面我们还有个比喻:餐馆点菜,菜谱中菜的品种类型成百上千,而顾客关心的是菜的色、香、味,做菜的过程大家都知道:配菜、炒菜、放调料、出锅。但是做的方法非常复杂,配的菜样不同,调料多少不同,烹饪时间不同…等等,但是厨师却能让同样的做菜流程,做不同的口味菜肴,呈现在顾客面前,而且不同的厨师能做出不同的美味,比如川菜厨师炒菜比较好吃,两湖的厨师对蒸菜比较拿手。对于厨师来说,就是把这种菜的制作过程与顾客点的菜分离,使得同样的做菜流程可以做出各种千变万化的美味。而厨师就是菜的建造者,菜是他们的产品。而服务员就是指挥者,餐馆顾客就是客户。
根据这个类图,我们模拟一个流程,顾客点了菜。服务员记下后通知厨房的厨师做菜,厨房里的张师傅会做川菜,而李师傅会做蒸菜。厨师做好菜后就传菜给服务员,服务员将菜给顾客端上。让我们看看代码如何实现:
/** 服务员 */ public class Waiter { // 做菜 public void carte(Master master) { master.garnish(); master.cooking(); master.condiments(); master.pan(); } }
/** * 建造者抽象接口--厨师 */ public abstract class Master { // 配菜 public abstract void garnish(); // 做菜 public abstract void cooking(); // 放入调料 public abstract void condiments(); // 出锅 public abstract void pan(); // 传菜 public abstract Vegetables pantry(); }
/** * 厨师--李师傅 */ public class ChefLee extends Master { protected Vegetables vegetables = new Vegetables(); // 配菜 public void garnish(){ vegetables.add("配好原料了"); } // 做菜 public void cooking(){ vegetables.add("蒸菜"); } // 放入调料 public void condiments(){ vegetables.add("放调料"); } // 出锅 public void pan(){ vegetables.add("菜炒好了!"); } // 传菜 public Vegetables pantry(){ return vegetables; } }
/** * 具体建造者--张师傅 */ public class ChefZhang extends Master{ protected Vegetables vegetables = new Vegetables(); // 配菜 public void garnish(){ vegetables.add("配好原料了"); } // 做菜 public void cooking(){ vegetables.add("下锅炒"); } // 放入调料 public void condiments( ){ vegetables.add("放调料"); } // 出锅 public void pan(){ vegetables.add("炒好了!"); } // 传菜 public Vegetables pantry(){ return vegetables; } }
/** * 具体产品--菜 */ public class Vegetables { // 菜的信息 private List<String> info = new ArrayList<String>(); // 菜的完成过程 public void add(String str){ info.add(str); } //做菜情况说明 public void explain(){ System.out.println("做菜流程:"); for(String s : info){ System.out.print(" " + s); } } }
/** * 客户端测试 */ public class Client { public static void main(String[] args) { // 点菜 Waiter waiter = new Waiter(); Master zhang = new ChefZhang(); Master lee = new ChefLee(); // 通知张师傅做菜 waiter.carte(zhang); Vegetables spicy = zhang.pantry(); // 菜做好了 spicy.explain(); // 通知李师傅做菜 waiter.carte(lee); Vegetables fish = lee.pantry(); // 菜做好了 fish.explain(); } }
适用性:
1、 创建复杂对象的算法需要独立于对象各个部分的创建和组合方式。
2、 对象的构造过程允许被构造的对象有不同的表现形式时
实现要点:
1、 组装和创建接口:Builder类的接口要足够泛化,能够实现各个具体的builder。
2、 产品没有抽象类:这是因为创建对象的算法复杂或是形式多样,因此没有必要也无可能抽象出一个抽象类
3、 Builder中的默认空函数,而不是纯虚函数:在C++中在派生类里只要改变感兴趣的方法,而不需要重新定义整个类的所有方法。
4、 Builder模式 主要用于“分步骤构建一个复杂的对象”。在这其中“分步骤”是一个稳定的乘法,而复杂对象的各个部分则经常变化。
5、 Builder模式主要在于应对“复杂对象各个部分”的频繁需求变动。其缺点在于难以应对“分步骤构建算法”的需求变动。
6、 Abstract Factory模式解决“系列对象”的需求变化,Builder模式解决“对象部分”的需求变化。Builder模式通常和Composite模式组合使用
参考文章:http://www.cnblogs.com/CS106A/archive/2012/06/03/2532763.html