建造者模式
这个是zmo_xu的java设计模式系列的第三章.这里需要说明一下 我这里给出的代码并不是标准代码,应该说是我自己的学习笔记,拿出来与大家交流,也希望各位高手多多指教,在这里感谢javastudy给予的帮助!(感谢CCTV ,感谢父母 感谢滚石娱乐的什么就不说了 呵呵 好了 老规矩 言归正传[保存下 哈哈 ])
概述
在软件系统中,有时候面临着“一个复杂对象”的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法确相对稳定。如何应对这种变化?如何提供一种“封装机制”来隔离出“复杂对象的各个部分”的变化,从而保持系统中的“稳定构建算法”不随着需求改变而改变?这就是要说的建造者模式。
本文通过现实生活中的买KFC的例子,用图解的方式来诠释建造者模式。
意图
将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。
[注意:所有的设计模式都不是为了使我们的代码更简单,正恰恰相反 是更复杂,设计模式的目的 是提高 代码的重用 降低模块的耦合]{打听下怎么用最快的方法把word 里面的图片发上来 ....相册的方法就不要说了...}
生活中的例子
生成器模式将复杂对象的构建与对象的表现分离开来,这样使得同样的构建过程可以创建出不同的表现。这种模式用于快餐店制作儿童餐。典型的儿童餐包括一个主食,一个辅食,一杯饮料和一个玩具(例如汉堡、炸鸡、可乐和玩具车)。这些在不同的儿童餐中可以是不同的,但是组合成儿童餐的过程是相同的。无论顾客点的是汉堡,三名治还是鸡肉,过程都是一样的。柜台的员工直接把主食,辅食和玩具放在一起。这些是放在一个袋子中的。饮料被倒入杯中,放在袋子外边。这些过程在相互竞争的餐馆中是同样的。
客户端:顾客。想去买一套套餐(这里面包括汉堡,可乐,薯条),可以有1号和2号两种套餐供顾客选择。
指导者角色:收银员。知道顾客想要买什么样的套餐,并告诉餐馆员工去准备套餐。
建造者角色:餐馆员工。按照收银员的要求去准备具体的套餐,分别放入汉堡,可乐,薯条等。
产品角色:最后的套餐,所有的东西放在同一个盘子里面。
下面开始我们的买套餐过程。
1.客户创建Derector对象,并用它所想要的Builder对象进行配置。顾客进入KFC店要买套餐,先找到一个收银员,相当于创建了一个指导者对象。这位收银员给出两种套餐供顾客选择:1普通套餐,2黄金套餐。完成的工作如时序图中红色部分所示。
[养成保存文件的习惯 web程序也不例外]
package unit3_Buider;
import java.util.ResourceBundle;
public class Client
{
public Client()
{
}
/**
* @param args
*/
public static void main(String[] args)
{
//设置配置文件 文件名
String configFile="food.properties";
FoodManager foodmanager = new FoodManager();
Builder instance;
System.out.println("Please Enter Food No:");
String No = 1+"";
ResourceBundle bundle = ResourceBundle.getBundle(configFile);
//String foodType = ConfigurationSettings.AppSettings["No" + No];
String foodType=bundle.getString("No"+No);
try
{
instance = (Builder) Class.forName(foodType).newInstance();
foodmanager.Construct(instance);
}
catch (InstantiationException e)
{
e.printStackTrace();
}
catch (IllegalAccessException e)
{
e.printStackTrace();
}
catch (ClassNotFoundException e)
{
e.printStackTrace();
}
}
}
唉又一次华丽的提交失败了
package unit3_Buider;
import java.util.Enumeration;
import java.util.Hashtable;
public class Food
{
Hashtable food = new Hashtable();
public void Add(String strName, String Price)
{
food.put(strName, Price);
}
public void Show()
{
System.out.println("Food List:");
System.out.println("------------------------------");
for (Enumeration e = food.elements(); e.hasMoreElements() ;) {
System.out.println(e.nextElement());
}
System.out.println("\n------------------------------");
}
}
保存点
2.指导者通知建造器。收银员(指导者)告知餐馆员工准备套餐。这里我们准备套餐的顺序是:放入汉堡,可乐倒入杯中,薯条放入盒中,并把这些东西都放在盘子上。这个过程对于普通套餐和黄金套餐来说都是一样的,不同的是它们的汉堡,可乐,薯条价格不同而已。如时序图红色部分所示:
package unit3_Buider;
public class FoodManager
{
public FoodManager()
{
}
public void Construct(Builder builder)
{
builder.BuildHamb();
builder.BuildCoke();
builder.BuildChip();
}
}
程序实现:
package unit3_Buider;
public abstract class Builder
{
public Builder()
{
}
public abstract void BuildHamb();
/*
* 添加可乐
*/
public abstract void BuildCoke();
/**
* 添加薯条
*/
public abstract void BuildChip();
/**
* 返回结果
* @return 食品对象
*/
public abstract Food GetFood();
}
今天就写到这里晚了 这样写好累的说 郁闷都没人顶下 动力啊 ....55555
具体的建造者
package zmo;
public class GoldBuilder extends Builder
{
//黄金套餐的配餐员
private Food goldFood=null;
public GoldBuilder()
{
this.goldFood=new Food();
}
@Override
public void BuildChip()
{
goldFood.Add("GoldChip", "5.00");
}
@Override
public void BuildCoke()
{
goldFood.Add("CokeCole", "5.00");
}
@Override
public void BuildHamb()
{
goldFood.Add("GoldHamb", "13.50");
}
@Override
public Food GetFood()
{
return goldFood;
}
}
package zmo;
public class NormalBuilder extends Builder
{
//普通套餐的配餐员
private Food normalFood=null;
public NormalBuilder()
{
normalFood=new Food();
}
@Override
public void BuildChip()
{
//添加薯条
normalFood.Add("FireChips", "2.00");
}
@Override
public void BuildCoke()
{
//添加可乐
normalFood.Add("cokecole", "5.00");
}
@Override
public void BuildHamb()
{
//添加汉堡
normalFood.Add("NormalHamb", "1.00");
}
@Override
public Food GetFood()
{
return normalFood;
}
}
package zmo;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ResourceBundle;
public class Client
{
//模拟顾客点菜
/**
* @param args
*/
public static void main(String[] args)
{
FoodManager foodmanager = new FoodManager();
Builder instance;
//设置配置文件 文件名
String configFile="food";
ResourceBundle bundle = ResourceBundle.getBundle(configFile);
String No="";
do
{
System.out.println(bundle.getString("List"));
No =inputString();
}while(No.equals("")||No==null);
String foodType = bundle.getString("No"+No);
//String foodType="zmo.NormalBuilder";
try
{
instance = (Builder) Class.forName(foodType).newInstance();
foodmanager.Construct(instance);
Food food=instance.GetFood();
food.Show();
}
catch (InstantiationException e)
{
e.printStackTrace();
}
catch (IllegalAccessException e)
{
e.printStackTrace();
}
catch (ClassNotFoundException e)
{
e.printStackTrace();
}
}
/**
* 用于从控制台获取输入
* @return
*/
private static String inputString()
{
BufferedReader bufferedreader = new BufferedReader(
new InputStreamReader(System.in));
String s = null;
try
{
s = bufferedreader.readLine();
} catch (IOException ioexception)
{
ioexception.printStackTrace();
}
return s;
}
}
追加说明:
实现要点
1、建造者模式主要用于“分步骤构建一个复杂的对象”,在这其中“分步骤”是一个稳定的算法,而复杂对象的各个部分则经常变化。
2、产品不需要抽象类,特别是由于创建对象的算法复杂而导致使用此模式的情况下或者此模式应用于产品的生成过程,其最终结果可能差异很大,不大可能提炼出一个抽象产品类。
3、创建者中的创建子部件的接口方法不是抽象方法而是空方法,不进行任何操作,具体的创建者只需要覆盖需要的方法就可以,但是这也不是绝对的,特别是类似文本转换这种情况下,缺省的方法将输入原封不动的输出是合理的缺省操作。
4、前面我们说过的抽象工厂模式(Abtract Factory)解决“系列对象”的需求变化,Builder模式解决“对象部分”的需求变化,建造者模式常和组合模式(Composite Pattern)结合使用。
效果
1、建造者模式的使用使得产品的内部表象可以独立的变化。使用建造者模式可以使客户端不必知道产品内部组成的细节。
2、每一个Builder都相对独立,而与其它的Builder无关。
3、可使对构造过程更加精细控制。
4、将构建代码和表示代码分开。
5、建造者模式的缺点在于难于应付“分步骤构建算法”的需求变动。
适用性
以下情况应当使用建造者模式:
1、需要生成的产品对象有复杂的内部结构。
2、需要生成的产品对象的属性相互依赖,建造者模式可以强迫生成顺序。
3、 在对象创建过程中会使用到系统中的一些其它对象,这些对象在产品对象的创建过程中不易得到。
应用场景
1、 根据properties文件或者class文件来知道builder
2、 .......
总结
建造者模式的实质是解耦组装过程和创建具体部件,使得我们不用去关心每个部件是如何组装的。