【java设计模式】之 建造者(Builder)模式

我们还是举上一节的例子:生产汽车。上一节我们通过模板方法模式控制汽车跑起来的动作,那么需求是无止境的,现在如果老板又增加了额外的需求:汽车启动、停止、鸣笛引擎声都由客户自己控制,他想要什么顺序就什么顺序,那该如何做呢?

1. 汽车无休止的改造

假如现在要生产两种车,奔驰和宝马,这两辆车都有共性,我们所需要关注的是单个车的运行过程,这才是老板所关心的点所在。我们先这样想,针对这个需求,我们要找到一个切入点,那就是产品类,每个车都是一个产品,那么在产品类中我们可以控制车的运行顺序,这样每个车都可以拥有自己想要的顺序了。基于此,我们设计如下类图:

我们看到CarModel中有个setSequence方法,通过传入一个ArrayList来控制运行顺序,run方法根据这个ArrayList中保存的顺序执行,然后奔驰车和宝马车分别继承这个CarModel即可,这貌似是很好的实现,它很像上一节的模板方法模式,只是多了个方法可以设置运行顺序。我们看一下CarModel具体代码的实现:

public abstract class CarModel {

	private ArrayList<String> sequence = new ArrayList<String>(); //维护一个ArrayList保存执行命令关键字

	protected abstract void start();
	protected abstract void stop();
	protected abstract void alarm();
	protected abstract void engineBoom();

	final public void run() {
		for(int i = 0; i < this.sequence.size(); i ++) { //根据ArrayList中保存的顺序执行相应的动作
			String actionName = this.sequence.get(i);
			if(actionName.equalsIgnoreCase("start")) {
				this.start(); //启动汽车
			} else if(actionName.equalsIgnoreCase("stop")) {
				this.stop(); //停止汽车
			} else if(actionName.equalsIgnoreCase("alarm")) {
				this.alarm(); //汽车鸣笛
			} else if(actionName.equalsIgnoreCase("engine boom")) {
				this.engineBoom(); //汽车轰鸣
			}
		}
	}

	final public void setSequence(ArrayList<String> sequence) { //获得执行顺序的命令,即一个ArrayList
		this.sequence = sequence;
	}
}

CarModel中的setSequence方法允许客户自己设置一个顺序,我们看看子类的实现:

public class BenzModel extends CarModel {

	@Override
	protected void start() {
		System.out.println("奔驰启动……");
	}

	@Override
	protected void stop() {
		System.out.println("奔驰停止……");
	}

	@Override
	protected void alarm() {
		System.out.println("奔驰鸣笛……");
	}

	@Override
	protected void engineBoom() {
		System.out.println("奔驰轰鸣");
	}

}
//宝马就略了……一样的

下面我们增加一个测试类实现该需求:

public class Client {

	public static void main(String[] args) {
		BenzModel benz = new BenzModel();
		//存放run顺序
		ArrayList<String> sequence = new ArrayList<String>();
		sequence.add("engine boom"); //老板说:跑之前先轰鸣比较帅!
		sequence.add("start");
		sequence.add("stop");
		//我们把这个顺序赋予奔驰
		benz.setSequence(sequence);
		benz.run();
	}
}

这样好像已经顺利完成了任务了,但是别忘了,我们这只是满足了一个需求,如果下一个需求是宝马车只轰鸣,再下一个需求是奔驰车只跑不停……等等……那岂不是要一个个写测试类来实现?显然这不是我们想要的。

我们可以这样做:为每种产品模型定义一个建造者,你要啥顺序直接告诉建造者,由建造者来建造即可,于是我们重新设计类图:

我们增加了一个CarBuilder类,由它来组装各个车模型,要什么类型的顺序就由相关的子类去完成即可,我们来看看CarBuilder的代码:

public abstract class CarBuilder {
	//建造一个模型,你要给我一个顺序要求
	public abstract void setSequence(ArrayList<String> sequence);
	//设置完毕顺序后,就可以直接拿到这个车辆模型了
	public abstract CarModel getCarModel();
}

很简单,每个车辆模型都要有确定的运行顺序,然后才能返回一个车辆模型,奔驰车和宝马车组装者的代码如下:

public class BenzBuilder extends CarBuilder {

	private BenzModel benz = new BenzModel(); //奔驰车模型

	@Override
	public void setSequence(ArrayList<String> sequence) {
		this.benz.setSequence(sequence); //设置奔驰车模型的运行顺序
	}

	@Override
	public CarModel getCarModel() {
		return this.benz; //将这个模型返回
	}
}
//宝马车一样,不写了……

现在两辆车的组装者都写好了,现在我们写一个测试类来测试一下:

public class Client {

	public static void main(String[] args) {

		//存放run顺序
		ArrayList<String> sequence = new ArrayList<String>();
		sequence.add("engine boom");
		sequence.add("start");
		sequence.add("stop");
	    //要用这个顺序造一辆奔驰
		BenzBuilder benzBuilder = new BenzBuilder();
		//把顺序给奔驰组装者
		benzBuilder.setSequence(sequence);
		//奔驰组装者拿到顺序后就给你生产一辆来
		BenzModel benz = (BenzModel) benzBuilder.getCarModel();
		benz.run();
	}

}

如果我要生产一辆宝马车,只需要换成宝马车的组装者即可,这样我们不用直接访问产品类了,全部访问组装者就行,是不是感觉到很方便,我管你怎么生产,我扔给你个顺序,你给我弄辆车出来,要的就是这种效果!

可是人的需求是个无底洞,特别是老板,他哪天不爽了,又要换顺序,这样还是挺麻烦的,四个过程(start、stop、alarm、engine boom)按排列组合也有很多中情况,我们不能保证老板想要哪种顺序,咋整?无奈,我们只能使出最后的杀手锏了,找个设计师过来指挥各个时间的先后顺序,然后为每种顺序指定一个代码,你说一种我们立刻就给你生产!我们再修改一下类图……

类图看着有点复杂,其实不然,只是在原来的基础上增加了一个Director类充当着设计师的角色,负责按照指定的顺序生产模型,比如我们要一个A顺序的奔驰车,B顺序的奔驰车,A顺序的宝马车,B顺序的宝马车……等等,我们来看下Director类的代码:

public class Director {
	private ArrayList<String> sequence = new ArrayList<String>();
	private BenzBuilder benzBuilder = new BenzBuilder();
	private BWMBuilder bwmBuilder = new BWMBuilder();

	//A顺序的奔驰车
	public BenzModel getABenzModel() {
		this.sequence.clear();
		this.sequence.add("start");
		this.sequence.add("stop");
		//返回A顺序的奔驰车
		this.benzBuilder.setSequence(sequence);
		return (BenzModel) this.benzBuilder.getCarModel();
	}

	//B顺序的奔驰车
	public BenzModel getBBenzModel() {
		this.sequence.clear();
		this.sequence.add("engine boom");
		this.sequence.add("start");
		this.sequence.add("stop");
		//返回B顺序的奔驰车
		this.benzBuilder.setSequence(sequence);
		return (BenzModel) this.benzBuilder.getCarModel();
	}

	//C顺序的宝马车
	public BenzModel getCBWMModel() {
		this.sequence.clear();
		this.sequence.add("start");
		this.sequence.add("alarm");
		this.sequence.add("stop");
		//返回C顺序的宝马车
		this.bwmBuilder.setSequence(sequence);
		return (BenzModel) this.bwmBuilder.getCarModel();
	}

	//D顺序的宝马车
	public BenzModel getDBWMModel() {
		this.sequence.clear();
		this.sequence.add("engine boom");
		this.sequence.add("start");
		//返回D顺序的宝马车
		this.bwmBuilder.setSequence(sequence);
		return (BenzModel) this.bwmBuilder.getCarModel();
	}

	//还有很多其他需求,设计师嘛,想啥需求就给你弄啥需求
}

有了这样一个设计师,我们的测试类就更容易处理了,比如现在老板要10000辆A类奔驰车,100000辆B类奔驰车,20000C类型宝马车,D类型不要:

public class Client {

	public static void main(String[] args) {

		Director director = new Director();

		for(int i = 0; i < 10000; i ++) {
			director.getABenzModel();
		}

		for(int i = 0; i < 100000; i ++) {
			director.getBBenzModel();
		}

		for(int i = 0; i < 20000; i ++) {
			director.getCBWMModel();
		}
	}

}

是不是很清晰很简单,我们重构代码的最终第就是简单清晰。这就是建造者模式。

2. 建造者模式的定义

我们来看看建造者模式的一般定义:Separate the construction of a complex object from its representation so that the same construction process can create different representations. 即:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。比如上面的例子,我们可以用同样的顺序构造不同的车。建造者模式的通用类图如下:

Product是最终的产品类,Builder是建造者,Director是指挥者。Director负责安排已有模块的顺序,然后告诉Builder开始建造。

3. 建造者模式的优点

1)封装性:使用建造者模式可以是客户端不必知道产品内部组成的细节。

2)建造者独立,容易扩展:BenzBuilder和BMWBuilder是相互独立的,对系统扩展非常有利。

3)便于控制细节风险:由于具体的建造者是独立的,因此可以对建造者过程逐步细化,而不对其他的模块产生任何影响。

4. 建造者模式的使用场景

1)相同的方法,不同的执行顺序,产生不同的事件结果时,可以使用建造者模式。

2)多个部件或零件,都可以装配到一个对象中,但是产生的运行结果又不想同时,可以使用建造者模式。

3)产品类非常复杂,或者产品类中的调用顺序不同产生了不同的效能,这时候可以使用建造者模式。

4)在对象创建过程中会使用到系统的一些其他对象,这些对象在产品对象的创建过程中不易得到,也可以采用建造者模式封装该对象的创建过程。这种场景只能是一个补偿的方法,因为一个对象不容易获得,而在设计阶段竟然没有发现,而要通过设计这模式来柔化创建过程,本身设计已经出问题了。

到这里,我们会发现,建造者模式和工厂方法模式有点像。但是两者有区别:建造者模式关注的是零件类型和装配工艺(顺序),而工厂模式是创建一个对象,这是最大不同的地方。

创建者模式就介绍这么多吧,如有错误之处,欢迎留言指正~

_____________________________________________________________________________________________________________________________________________________

-----乐于分享,共同进步!

-----更多文章请看:http://blog.csdn.net/eson_15

时间: 2024-10-09 10:27:34

【java设计模式】之 建造者(Builder)模式的相关文章

设计模式之建造者(Builder)模式

意图 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以表示不同的表示. 适用性 当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时. 当构造过程必须允许被构造的对象有不同的表示时. UML图 Builder --为创建一个Product对象的各个部件指定抽象接口. ConcreteBuilder --实现Builder的接口以构造和装配该产品的各个部件. --定义并明确它所创建的表示. --提供一个检索产品的接口. Director --构造一个使用Builder接口的

java设计模式4--建造者模式(Builder)

本文地址:http://www.cnblogs.com/archimedes/p/java-builder-pattern.html,转载请注明源地址. 建造者模式 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示. 概述 当系统准备为用户提供一个内部结构复杂的对象时,就可以使用生成器模式,使用该模式可以逐步地构造对象,使得对象的创建更具弹性.生成器模式的关键是将一个包含有多个组件对象的创建分成若干个步骤,并将这些步骤封装在一个称作生成器的接口中. 适用性 1.当创建复杂

Java 实现建造者(Builder)模式

建造者(Builder)模式是创建型模式,创建了一个对外隐藏创建过程的产品,使用组合的方式,由指挥者(Director)来决定建造的流程 public interface Builder { void buildPartA(); void buildPartB(); void buildPartC(); } public class BuilderImpl implements Builder { @Override public void buildPartA() { System.out.p

建造者(Builder)模式

在学习MyBatis的过程中遇到了建造者(Builder)模式,查找了相关资料,在这做下记录加深印象. 参考资料: java设计模式-建造者模式(Builder) 人人都会设计模式---建造者模式--Builder <JAVA与模式>之建造模式 1.什么是建造者模式 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示,通俗的说就是:建造者模式就是如何一步步构建一个包含多个组成部件的对象,相同的构建过程可以创建不同的产品. 2.一个组装电脑的示例 小明想组装一个台式电脑,小

折腾Java设计模式之中介者模式

博文原址:折腾Java设计模式之中介者模式 中介者模式 中介者模式(Mediator Pattern)是用来降低多个对象和类之间的通信复杂性.这种模式提供了一个中介类,该类通常处理不同类之间的通信,并支持松耦合,使代码易于维护.中介者模式属于行为型模式. 通俗点来讲就是提供一个中介平台,说到平台,那其实很容易联系到我们很熟悉的房地产中介.我们可以直接通过这个平台得到我们想要的信息,不用对象自身与其他对象交互. 买房子租房子就不需要去找房东,只需要在中介那里获取相应的×××信息.如下图那样,两方只

一起学java设计模式--适配器模式(结构型模式)

适配器模式 现有一个接口DataOperation定义了排序方法sort(int[]) 和查找方法search(int[], int),已知类QuickSort的quickSort(int[])方法实现了快速排序算法,类BinarySearch 的binarySearch(int[], int)方法实现了二分查找算法.现使用适配器模式设计一个系统,在不修改源代码的情况下将类QuickSort和类BinarySearch的方法适配到DataOperation接口中.绘制类图并编程实现. (要求实现

Java设计模式之接口型模式总结

摘要: 原创作品,可以转载,但是请标注出处地址:http://www.cnblogs.com/V1haoge/p/6508967.html 之前认真学习了Java设计模式中的四大接口型模式,分别为:适配器模式(Adapter).外观模式(Facade).合成模式(Composite).桥接模式(Bridge). 1.在此处再温习一下四种设计模式: (1)适配器模式: 我们能够访问的类中不存在我们要访问的内容时,就可以使用这个适配器模式,当然就类而言,其实不存在什么不能被访问,这里的不能访问都是人

Java设计模式之工厂方法模式(转) 实现是抽象工厂?

Java设计模式之工厂方法模式 责任编辑:覃里作者:Java研究组织   2009-02-25   来源:IT168网站 文本Tag: 设计模式 Java [IT168 技术文章]          一 .工厂方法(Factory Method)模式 工厂方法模式的意义是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类当中.核心工厂类不再负责产品的创建,这样核心类成为一个抽象工厂角色,仅负责具体工厂子类必须实现的接口,这样进一步抽象化的好处是使得工厂方法模式可以使系统在不修改具体工厂角色

Java设计模式之结构型模式

结构型设计模式是从程序的结构上解决模块之间的耦合问题.包括以下七种模式: 适配器模式:可以将类的一个借口匹配另一个接口 组合模式:对象的组合 代理模式:一个简单的对象代替一个复杂的稍后会被调用的复杂对象 外观模式:一个类表示一个子系统 享元模式:用于共享对象,其中每个实例都不保存自己的状态.而是将状态保存在外部 桥接模式:将对象的接口与实现分离 装饰模式:动态给对象添加职责结构型设计模式是从程序的结构上解决模块之间的耦合问题 适配器模式: 原文链接:一个示例让你明白适配器模式 含义:将一个类的接

java设计模式之 装饰器模式

适AT java设计模式之 装饰器模式 装饰器模式 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构. 这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装. 这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,动态给一个对象添提供了额外的功能. 我们通过下面的实例来演示装饰器模式的用法.模拟一个人从想吃饭.找饭店.享受美食.结束吃饭的过程 代码展示: 首先创建一个被修饰的接口 Eat package deco