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