有句俗话叫懒人屎尿多!我也不知道我这是怎么回事,懒得要死,还写这么多,这例子那例子的,挺啰嗦的!
昨天的工厂方法和抽象工厂模式写了N多,今天真不想写,可是总觉得,不写的话我哪有机会吹水,还是写吧!(真是个坏人,不考虑看的人感受,拜托不要总是成全自己恶心别人好不!!!)
说起这个建造者模式,我们还是继续昨天createHuman的故事继续编吧!
昨天说到create了各种人,有白的、黑的,黄的,还有男的、女的,他们都会说会笑。很好,但是有人喜欢先说在笑,有的人喜欢先笑再说,每个人都有自由,想什么顺序就什么顺序,这个可以吧?Of course!
为了人类的自由,我得有鞠躬尽瘁死而后已的决心Code出来才行!
首先,昨天的Human要upgrade一下才行。
package com.freedom.builder2;
import java.util.ArrayList;
public abstract class HumanModel{
// 存放各个基本方法执行的顺序
private ArrayList<String> sequence = new ArrayList<String>();
public abstract void say();
public abstract void smile();
final public void <span><span>createHuman</span></span>() {
//使用数组的遍历,确定那个先执行
for (int i = 0; i < this.sequence.size(); i++) {
String actionName = this.sequence.get(i);
if (actionName.equalsIgnoreCase("say")) {
this.say();
} else if (actionName.equalsIgnoreCase("smile")) {
this.smile();
}
}
}
// setSequence 方法是允许客户自己设置一个顺序,把传递过来的值传递到类内
final public void setSequence(ArrayList<String> sequence) {
this.sequence = sequence;
}
}
package com.freedom.builder2;
public class WhiteHuman extends HumanModel{
@Override
public void say() {
System.out.println("white human can say anything!");
}
@Override
public void smile() {
System.out.println("white human can smile!");
}
}
package com.freedom.builder2;
public class BlackHuman extends HumanModel{
@Override
public void say() {
System.out.println("black human can say anything!");
}
@Override
public void smile() {
System.out.println("black human can smile!");
}
}
package com.freedom.builder2;
import java.util.ArrayList;
import org.junit.Test;
public class TestBuilder {
@Test
public void client() {
/*
* 客户说我要你给我create一个白人,先笑再说的;还要一个黑人,先说再笑的。
*/
HumanModel whiteHuman = new WhiteHuman();
ArrayList<String> sequence = new ArrayList<String>(); //存放run的顺序
sequence.add("smile"); //客户要求,先笑
sequence.add("say"); //再说话
//然后把这个顺序给白人:
whiteHuman.setSequence(sequence);
whiteHuman.r<span><span>createHuman</span></span>un();
HumanModelblackHuman = new BlackHuman();
ArrayList<String> sequence2 = new ArrayList<String>(); //存放run的顺序
sequence2.add("say"); //客户要求,先说话
sequence2.add("smile"); //再微笑
//然后把这个顺序给黑人:
blackHuman.setSequence(sequence2);
blackHuman.<span><span>createHuman</span></span>();
}
}
/*
运行结果:
white human can smile!
white human can say anything!
black human can say anything!
black human can smile!
*/
这还不能实现想怎样就怎样,只能满足一开始生产就订好顺序的,每次都要给人定义顺序,一两个无所谓,N个呢,一会先笑,一会先说,会疯的,下面继续改造,增加一个 HumanBuilder 的抽象类,以及两个实现类,其目的是你要那人先笑就先笑,先说话就先说话。
package com.freedom.builder2;
import java.util.ArrayList;
public abstract class HumanBuilder {
//建造一个模型,给我一个顺序,我就create这个顺序的人模型
public abstract void setSequence(ArrayList<String> sequence);
//设置完毕顺序后,直接拿到这个人模型
public abstract HumanModel getHumanModel();
}
package com.freedom.builder2;
import java.util.ArrayList;
public class WhiteHumanBuilder extends HumanBuilder{
private WhiteHuman whiteHuman = new WhiteHuman();
@Override
public void setSequence(ArrayList<String> sequence) {
this.whiteHuman.setSequence(sequence);
}
@Override
public HumanModel getHumanModel() {
return this.whiteHuman;
}
}
package com.freedom.builder2;
import java.util.ArrayList;
public class BlackHumanBuilder extends HumanBuilder{
private BlackHuman blackHuman = new BlackHuman();
@Override
public void setSequence(ArrayList<String> sequence) {
this.blackHuman.setSequence(sequence);
}
@Override
public HumanModel getHumanModel() {
return this.blackHuman;
}
}
//Test
package com.freedom.builder2;
import java.util.ArrayList;
import org.junit.Test;
public class TestBuilder2 {
@Test
public void client() {
//客户说我要你给我先笑再说的
ArrayList<String> sequence = new ArrayList<String>(); //存放run的顺序
sequence.add("smile"); //客户要求,先笑
sequence.add("say"); //再说话
//要一个白人
WhiteHumanBuilder whiteHumanBuilder = new WhiteHumanBuilder();
whiteHumanBuilder.setSequence(sequence);
WhiteHuman whiteHuman = (WhiteHuman) whiteHumanBuilder.getHumanModel();
whiteHuman.createHuman();
//要一个黑人
BlackHumanBuilder blackHumanBuilder = new BlackHumanBuilder();
blackHumanBuilder.setSequence(sequence);
BlackHuman blackHuman = (BlackHuman) blackHumanBuilder.getHumanModel();
blackHuman.createHuman();
}
}
/*
运行结果:
white human can smile!
white human can say anything!
black human can smile!
black human can say anything!
*/
看,是不是比刚开始直接访问产品类(HumanModel)简单了很多吧,那还有个这样的需求,这两个过程(say,smile)结合不同人种按照排列组合有多种,那我们怎么满足这种需求呢?要有个类来安排这几个方法组合,就像导演安排演员一样,那个先出场那个后出场,那个不出场,我们把这个类叫导演类(Director)。
package com.freedom.builder2;
import java.util.ArrayList;
public class Director {
private ArrayList<String> sequence = new ArrayList();
private WhiteHumanBuilder whiteHumanBuilder = new WhiteHumanBuilder();
private BlackHumanBuilder blackHumanBuilder = new BlackHumanBuilder();
//A型白人
public WhiteHuman getAHumanModel() {
// 清理场景,这里一定要注意
this.sequence.clear();
// 这只WhiteHuman的执行顺序
this.sequence.add("say");
this.sequence.add("simle");
// 按照顺序返回一个先会说再会笑的白人
this.whiteHumanBuilder.setSequence(this.sequence);
return (WhiteHuman) this.whiteHumanBuilder.getHumanModel();
}
//B型白人
public WhiteHuman getBHumanModel() {
// 清理场景,这里一定要注意
this.sequence.clear();
// 这只WhiteHuman的执行顺序
this.sequence.add("simle");
this.sequence.add("say");
// 按照顺序返回一个先会笑再会说的白人
this.whiteHumanBuilder.setSequence(this.sequence);
return (WhiteHuman) this.whiteHumanBuilder.getHumanModel();
}
//C型黑人
public BlackHuman getCHumanModel() {
// 清理场景,这里一定要注意
this.sequence.clear();
// 这只WhiteHuman的执行顺序
this.sequence.add("say");
this.sequence.add("smile");
// 按照顺序返回一个先会说再会笑的黑人
this.blackHumanBuilder.setSequence(this.sequence);
return (BlackHuman) this.blackHumanBuilder.getHumanModel();
}
//D型黑人
public BlackHuman getDHumanModel() {
// 清理场景,这里一定要注意
this.sequence.clear();
// 这只WhiteHuman的执行顺序
this.sequence.add("simle");
this.sequence.add("say");
// 按照顺序返回一个先会笑再会说的黑人
this.blackHumanBuilder.setSequence(this.sequence);
return (BlackHuman) this.blackHumanBuilder.getHumanModel();
}
}
程序中有很多this 调用,属于个人人习惯,如果你要调用类中的成员变量或方法,在前面加上this 关键字,不加也能正常的跑起来,但是不清晰,加上this 关键字,明确我就是要调用本类中成员变量或方法,而不是本方法的中的一个变量,还有super 方法也是一样,是调用父类的的成员变量或者方法,最好加上这个关键字,不要省略。
上面每个方法都一个this.sequence.clear(),这个估计一看就明白,ArrayList 和HashMap 如果定义成类的成员变量,那在方法中调用一定要做一个clear 的动作,防止数据混乱,这个如果曾经我亲身经历过一次,ArrayList 中出现一个“出乎意料”的数据,花费了几个通宵才解决这个问题,印象够深刻!
然后 Client 程序就只与Director 打交道了,比如我只要要A 型的白人1W 只,B 型的白人100W只,C 型的黑人1000W ,D 型黑人不要:
package com.freedom.builder2;
import org.junit.Test;
public class TestBuilder3 {
@Test
public void client() {
Director director = new Director();
// 1W只A型的白人
for (int i = 0; i < 10000; i++) {
director.getAHumanModel().run();
}
// 100WB型的白人
for (int i = 0; i < 1000000; i++) {
director.getBHumanModel().run();
}
// 1000WC型的黑人
for (int i = 0; i < 10000000; i++) {
director.getCHumanModel().run();
}
}
}
/*
结果可想而知,不贴了!
*/
清晰简单吧?!写程序重构的最终目的就是简单清晰,让人一目了然,而不是写完就完事了,Java 程序不是像二进制代码、汇编那样,写完基本上就自己能看懂,别人看就跟看天书一样,和蝌蚪文没什么差别,高级语言,要像用中文汉字写小说写故事一样,你写的,别人一眼能看懂。整个程序编写完毕,简洁明了,这就是建造者模式,最后我们来小结一下:
Client() 就是客户,这具体的应用中的需求提供者;
HumanModel 以及两个实现类WhiteHuman和BlackHuman叫做产品类(Product Class),这个产品类实现了模板方法模式,也就是有模板方法和基本方法,这个参考上一节的模板方法模式;
HumanBuilder 以及两个实现类WhiteHumanBuilder 和BlackHumanBuilder 叫做建造者(Builder Class),在上面的例子中就是我建造WhiteHuman和BlackHuman人模,按照指定的顺序;
Director 类叫做导演类(Director Class),负责安排已有模块的顺序,然后告诉Builder 开始建造,客户需要什么人告诉我,我开始拼命的build,于是就没然后了。
看到这里估计就开始犯迷糊了,这个建造者模式和工厂模式有区别吗?有的,虽然有点相似。
记住一点就可以游刃有余的使用了:建造者模式最主要功能是基本方法的调用顺序安排,也就是这些基本方法已经实现了;而工厂方法则重点是创建,你要什么对象我创造一个对象出来,组装顺序则不是他关心的。
建造者模式的使用场景:
一是产品类非常的复杂,或者产品类中的调用顺序不同产生了不同的效能,这个时候使用建造者模式是非常合适,比如银行交易类项目中,一个产品的定价计算模型有N 多种,每个模型有固定的计算步骤,计算非常复杂,项目中就使用了建造者模式;
二是“ 在对象创建过程中会使用到系统中的一些其它对象,这些对象在产品对象的创建过程中不易得到”,这个是我还没有遇到过的,创建过程中不易得到?那为什么在设计阶段不修正这个问题,创建的时候都不易得到耶!要去找产品经理因为设计扯皮还不如乖乖想象代码怎么才具有更强大的拓展性!
Over!
下载源码:http://download.csdn.net/detail/github_22022001/8294697