前言:这个模式看了很长时间,反反复复,也没理解多少,当然主要还是现实代码开发中未遇到过类似的场景是需要使用到builder模式的,可能做的项目都不够复杂吧,所以还是转载一篇我个人认为解释不错的文章来的比较实际,待自己在现实项目中遇到过后,再来写具体的感受,网上对于builder模式的例子都是汽车类例子,所以除此之外我会继续补充一个迷宫的例子加深大家影响,主要我个人认为这两个场景是使用到builder模式的典型场景。下面是我转载的原文内容:来自:http://dev.csdn.net/htmls/14/14780.html
---------------------------------------------------------------转载开始--------------------------------------------------------------------------
当初我学这个设计模式的时候,怎么都搞不懂它和工厂模式到底有什么区别,而且看了很多别人实现的源代码,似乎都是在模仿工厂模式的实现。并没有突出Builder与Factory的本质差别。实际上,就我的理解,既然Builder和Factory同属创建型模式,那么他们的最大共同点就在于都可以创建类对象,在这点上,不光这两个模式一样,其它创建型模式也一样。但正如我在《深入探索Factory模式与Prototype模式的异同(续)》一文中所说,这些模式,功能上的相似,只是“形似而非神似”。既然这样,那好,下面就让我们能看看Builder和Factory在功能的相似上,存在哪些神韵方面的差别。
首先,也是最重要的一点,就是虽然Builder和Factory都可创建产品,但两者所创建的产品类型完全不一样。Factory创建只能是单一的产品(单一在这指它非复合产品),而Builder所创建的产品是复合产品,即产品本身就是由其它部件产品组成的。举个例子来说,现在要生产一辆车,假设它就只由这三个部分组成:玻璃、轮子、发动机。对于工厂模式来说,他创建后返回的,只能是玻璃,或者轮子,抑或是发动机。不管怎么样,他不能向客户返回一辆完整的汽车,要得到一辆完整的汽车,客户必须自己动手去把这些零部件组装成一辆汽车。从这个意义上来讲,工厂模式中的工厂,只是充当了零件厂的角色。那Builder又是如何创建产品的呢?在Builder模式中,一般不需要、也不充许向客户返回单个部件,他向客户返回的,仅仅就是一部已经完全组装好的汽车成品。对于汽车部件的生产细节,客户不需要、也不应该让他们知道。写到这,我突然想到了组装电脑与品牌电脑的差别,组装电脑虽然价格便宜,且易于改动,但性能没有保证,另外你自己还必须了解很多有关电脑方面的知识;对于品牌电脑,价格贵这点先暂时不说,关键在于他不灵活,但是它的性能可以得到很好保证(由厂家),这易像我们在Builder的系统端保证部件的质量一样。另外,对于品牌电脑,客户根本不需要了解多少电脑组装方面的知识,就可以把一台电脑抱回家,开机使用了。那么,在实际运用中,你是喜欢做DIY一族呢,还是喜欢稳定有保证的质量呢?好像在我们编著程的这个过程中,我们比较趋向于使用“品牌电脑”。这也就为我们正确使用这两种设计模式提供了一个方向:如果你要生产的产品是由不同部件组成的,你最好使用Builder模式,而非Factory模式。
另外,Builder和Factory的差别,就在于他们所生产部件产品所在产品树的问题。这样说,可能有点拗口。具体来说吧,在工厂模式中,我们知道,一个工厂可以创建多个产品,但一个工厂模式中所创建的某个产品,都会和另一个工厂中所创建的产品在同一棵继承树上。如果大家看过我最早写的《用Java实现的设计模式系列(1)—Factory 》那篇文章,就会记得,我在CFactoryMac中创建了一种产品叫MacRam,而在CFactoryWin中创建了另一种产品叫WinRam,很显然,这两种产品是在同一棵继承树上的。对于它们之所以会出现在同一棵继承树上,是完全由Factory模式本身所决定的。大家如果看过Factory的UMl图,就应该记得,要实现Factory模式,一定要有一个Abstract Product类,具体产品再由它派生出来。好了,说完了Factory,再让我们来看看Builder中是否必这么做!实际上,在Builder模式中,我们只是在Abstract Builder中封装了创建部件的接口,而具体创建了什么部件,不同的实际Builder可能会生产出完全不一样的部件,这样不会存在任何问题,因为,我上面说过,Builder只是向客户返回成品,而不向客户返回具体部件,这样,当然就充许产品的部件按要求随意变化了。再举个例子吧,假如你现在要创建两种风马不相及的东西,例如一种是人,它就只由这几部分组成:脑、身、四肢;另一种是树,也由三个部分组成:根、叶、茎。好了,你现在要用Builder模式创建出这两种产品,能不能做到呢?看看下面的代码就明白了:
interface ABuilder{
public void builderPartA();
public void builderPartB();
public void builderPartC();
}
class CBuilderHuman implements ABuilder {
private Human human;
public CBuilderHuman() {
human=new Human();
}
public void builderPartA(){human.head=new Head()};
public void builderPartB(){human.body=new Body()};
public void builderPartC()(human.limb=new Limb()};
public Human getProduct(){
builderPartA();
builderPartB();
builderPartC();
return human;
}
class CBuilderTree的代码类似,这里就不写了。
再来看客户端代码:
public stacic void main(String[] args) {
CBuilderHuman builderhuman=new CBuilderHuman();
CBuilderTree buildertree=new CBuilderTree();
Human man;
Tree tree;
man=builderman.getProduct();
tree=buildertree.getProduct();
}
看了上面的代码,相信大家对于Factory与Builder的产品树问题已有了清楚的认识。虽然,Builder模式可以创建出风马不相及的产品,但一般我们不会这么做。更常见的运用是部件产品在同一棵继承树上。这样做的原因,大家想想面向对象的本质目的也就明白了。
好了,随手写写,想不到就写了这么一大篇。还是那句话,代码说明一切,那接下来,就让我们来看代码吧!
/**
* Design Pattern In Java
* Name:Builder
* 目的:利用Builder模式创建两种汽车carA和carB
* Car=Glass+Wheel+Engine
* carA=AmericanGlass+JapaneseWheel+ChinaEngine
* carB=JapaneseGlass+AmericanWheel+FranceEngine
* A:abstract
* C:Concret
* Author:blackphoenix
* Modify Date:2002-08-19
*/
/**
* 定义部件Glass的抽象类AClass
* 和两个具体类AmericanGlass、JapaneseGlass
*/
abstract class AGlass{
}
class AmericanGlass extends AGlass{
public String toString(){
return "/"American Glass/" ";
}
}
class JapaneseGlass extends AGlass{
public String toString(){
return "/"Japanese Glass/" ";
}
}
/**
* 定义部件Wheel的抽象类AWheel
* 和两个具体类AmericanWheel、JapaneseWheel
*/
abstract class AWheel{
}
class AmericanWheel extends AWheel{
public String toString(){
return "/"American Wheel/" ";
}
}
class JapaneseWheel extends AWheel{
public String toString(){
return "/"Japanese Wheel/" ";
}
}
/**
* 定义部件Engine的抽象类AEngine
* 和两个具体类ChineseEngine、FranceEngine
*/
abstract class AEngine{
}
class ChineseEngine extends AEngine{
public String toString(){
return "/"Chinese Engine/" ";
}
}
class FranceEngine extends AEngine{
public String toString(){
return "/"France Engine/" ";
}
}
/**
* 定义产品类Car
*/
class Car{
AGlass glass;
AWheel wheel;
AEngine engine;
}
/**
* 定义抽象建造器接口ABuilder
*/
interface ABuilder{
public void buildGlass();
public void buildWheel();
public void buildEngine();
}
/**
* 具体建造器类CBuilderCarA
* carA=AmericanGlass+JapaneseWheel+ChineseEngine
*/
class CBuilderCarA implements ABuilder{
private Car product=null;
public CBuilderCarA(){
product=new Car();
}
public void buildGlass(){
product.glass=new AmericanGlass();
}
public void buildWheel(){
product.wheel=new JapaneseWheel();
}
public void buildEngine(){
product.engine=new ChineseEngine();
}
/**
* 将建造部件的工作封装在getProduct()操作中,主要是为了向客户隐藏实现细节
* 这样,具体建造类同时又起到了一个Director的作用
*/
public Car getProduct(){
buildGlass();
buildWheel();
buildEngine();
return product;
}
}
/**
* 具体建造器类CBuilderCarB
* carB=JapaneseGlass+AmericanWheel+FranceEngine
*/
class CBuilderCarB implements ABuilder{
private Car product;
public CBuilderCarB(){
product=new Car();
}
public void buildGlass(){
product.glass=new JapaneseGlass();
}
public void buildWheel(){
product.wheel=new AmericanWheel();
}
public void buildEngine(){
product.engine=new FranceEngine();
}
/**
* 将建造部件的工作封装在getProduct()操作中,主要是为了向客户隐藏实现细节
* 这样,具体建造类同时又起到了一个Director的作用
*/
public Car getProduct(){
buildGlass();
buildWheel();
buildEngine();
return product;
}
}
/**
* 客户端代码,使用Builder创建两种不同型别的carA和carB
*/
public class Builder{
public static void main(String[] args){
Builder client=new Builder();
Car carA,carB;
CBuilderCarA builderA;
CBuilderCarB builderB;
builderA=new CBuilderCarA();
builderB=new CBuilderCarB();
carA=builderA.getProduct();
carB=builderB.getProduct();
System.out.println("Car A is made by:"+carA.glass+carA.wheel+carA.engine);
System.out.println("Car B is made by:"+carB.glass+carB.wheel+carB.engine);
}
}
---------------------------------------------------------------转载结束--------------------------------------------------------------------------
后续:
builder模式的参与对象有:
Builder----为创建一个Product对象的各个部件指定抽象接口
ConcreteBuilder----实现Builder的接口以构造和装备该产品的各个部件。
----定义并明确它所创建的表示。
----提供一个检索产品的接口
Director----构造一个使用Builder接口的对象。
Product----表示被构造的复杂对象。ConcreteBuilder创建该产品的内部表示并定义它的装备过程。
----包含定义组成部件的类,包括将这些部件装备成最终产品的接口。
Abstract factory模式参与对象有:
AbstractFactory----声明一个创建抽象产品对象的操作接口
ConcreteFactory----实现创建具体产品对象的操作。
AbstractProduct----为一类产品对象声明一个接口.
ConcreteProduct----定义一个将被相应的具体工厂创建的产品对象。
----实现AbstractProduct接口
Client ----仅使用由AbstractFactory和AbstractProduct类声明的接口.
综看builder模式和Abstract factory模式的参与对象,可以发现abstract factory参与对象的product必须继承AbstractProduct对象,也就是说Abstract factory模式中的产品其实是一系列相关的产品。而在builder模式中,对于product没有这个规定,因此个人认为这是两个模式中最大的区别.builder模式中的ConcreteBuilder和Abstract factory模式中的ConcreteFactory其实功能很相似,都是创建具体的产品了,只是创建的细节不同,前者是通过组合的方式创建对象。
另外补充的迷宫的例子。注意,为了比较builder模式与Abstract factory模式的区别,所以这里的例子是通过Abstractory factory的例子改造成builder模式,便于理解两者的区别,虽然有点改的不伦不类,见谅。
------------------Builder类-------------------
package com.gof.chapter3.builder.maze;
/**
* 定义了builder产生子产品的方法
* @author ben
*/
public abstract class MazeBuilder {
public abstract void BuilderMaze();
public abstract void BuilderRoom(String roomNo);
public abstract void BuilderDoor(String roomFromNo,String roomToNo);
public abstract Maze GetMaze();
public Direction commonWall(Room roomFrom,Room roomTo){
//这个程序主要用与返回门在房间的方向,这里偷懒返回固定值
return Direction.East;
}
protected Maze maze;
}
---------------Director类------------------
package com.gof.chapter3.builder.maze;
/**
*使用MazeBuilder来构建最终产品
**/
public class MazeGame {
public Maze createMaze(MazeBuilder builder){
builder.BuilderMaze();
builder.BuilderRoom("1");
builder.BuilderRoom("2");
builder.BuilderDoor("1", "2");
return builder.GetMaze();
}
public Maze createComplexMaze(MzeBuilder builder){
builder.BuilderMaze();
builder.BuilderRoom("1");
//.......
//.......
return builder.GetMaze();
}
}
-----------Maze类,我们要创建的产品--------------------
package com.gof.chapter3.builder.maze;
import com.gof.chapter3.builder.maze.Room;
public class Maze {
private java.util.List<Room> rooms = null;
public Maze(){
rooms = new java.util.ArrayList<Room>();
System.out.println("产生了一个迷宫对象..........");
}
public void setRoom(Room room){
rooms.add(room);
}
public Room getRoom(String roomNo){
for(Room room : rooms){
if(roomNo.equals(room.getRoomNo()))return room;
}
return null;
}
public boolean haveRoom(String roomNo){
for(Room room : rooms){
if(roomNo.equals(room.getRoomNo()))return true;
}
return false;
}
}
---------下面是产品的虚类,基本为了abstract factory兼容而存在的,如果纯粹是builder模式就不需要这些类了---------
package com.gof.chapter3.builder.maze;
/**
*房间,门,墙的接口
**/
public interface MapSite {
public abstract Object enter();
}
package com.gof.chapter3.builder.maze;
/**
*方向
**/
public enum Direction {
North,East,South,West
}
package com.gof.chapter3.builder.maze;
/**
* 房间虚类
*/
public abstract class Room implements MapSite{
public abstract Object enter() ;
public abstract void setSide(Direction direction,MapSite site);
public abstract MapSite getSide(Direction direction);
public abstract String getRoomNo();
protected String roomNo;
}
package com.gof.chapter3.builder.maze;
/**
* 门虚类
*/
public abstract class Door implements MapSite{
public abstract Object enter();
}
package com.gof.chapter3.builder.maze;
/**
* 墙虚类
*/
public abstract class Wall implements MapSite{
public abstract Object enter();
}
---------------------------------------------这里是具体产品类,就算是纯粹的builder类也是需要的哦------------------------------------
package com.gof.chapter3.builder.maze.common;
import java.util.HashMap;
import java.util.Map;
import com.gof.chapter3.builder.maze.Direction;
import com.gof.chapter3.builder.maze.MapSite;
import com.gof.chapter3.builder.maze.Room;
/**
* 产品,房间
*/
public class CommonRoom extends Room {
private Map sides = null;
public CommonRoom(String _roomNo) {
this.roomNo = _roomNo;
System.out.println("建立了一个普通的房间..........");
sides = new HashMap();
}
public Object enter() {
return null;
}
public void setSide(Direction direction, MapSite site) {
// just 设置
sides.put(direction, site);
}
public MapSite getSide(Direction direction) {
if (sides.get(direction) != null) {
return (MapSite) sides.get(direction);
} else {
return null;
}
}
@Override
public String getRoomNo() {
// TODO Auto-generated method stub
return this.roomNo;
}
}
package com.gof.chapter3.builder.maze.common;
import com.gof.chapter3.builder.maze.Door;
import com.gof.chapter3.builder.maze.Room;
/**
* 产品,门
*/
public class CommonDoor extends Door{
private Room roomFrom;
private Room roomTo;
public CommonDoor(Room _roomFrom,Room _roomTo){
this.roomFrom = _roomFrom;
this.roomTo = _roomTo;
System.out.println("建立了一个普通的门.........");
}
@Override
public Object enter() {
// TODO Auto-generated method stub
return null;
}
}
package com.gof.chapter3.builder.maze.common;
import com.gof.chapter3.builder.maze.Wall;
/**
* 产品,墙
*/
public class CommonWall extends Wall{
public CommonWall(){
System.out.println("建立了一个普通的墙.............");
}
@Override
public Object enter() {
// TODO Auto-generated method stub
return null;
}
}
----------------------ConcreteBuilder类,生成各产品部件的具体实现类-----------------
package com.gof.chapter3.builder.maze.common;
import com.gof.chapter3.builder.maze.Direction;
import com.gof.chapter3.builder.maze.Door;
import com.gof.chapter3.builder.maze.Maze;
import com.gof.chapter3.builder.maze.MazeBuilder;
import com.gof.chapter3.builder.maze.Room;
public class CommonMazeBuilder extends MazeBuilder{
public CommonMazeBuilder(){
//~~
}
@Override
public void BuilderDoor(String roomFromNo, String roomToNo) {
Room roomFrom = this.maze.getRoom(roomFromNo);
Room roomTo = this.maze.getRoom(roomToNo);
Door door = new CommonDoor(roomFrom,roomTo);
roomFrom.setSide(this.commonWall(roomFrom, roomTo), door);
roomTo.setSide(this.commonWall(roomTo, roomFrom), door);
}
@Override
public void BuilderMaze() {
// TODO Auto-generated method stub
this.maze = new Maze();
}
@Override
public void BuilderRoom(String roomNo) {
if(!this.maze.haveRoom(roomNo)){
Room room = new CommonRoom(roomNo);
room.setSide(Direction.East, new CommonWall());
room.setSide(Direction.North, new CommonWall());
room.setSide(Direction.South, new CommonWall());
room.setSide(Direction.West, new CommonWall());
this.maze.setRoom(room);
}
}
@Override
public Maze GetMaze() {
// TODO Auto-generated method stub
return this.maze;
}
}
- abstrac factory模式中的:CommonMazeFactory是具体创建对象的工厂类,这个类不但能生成部件,而且还将最终产品返回
- builder模式中的:CommonMazeBuilder主要功能是创建产品对象,比如门,房间和迷宫,并且建立这些部件创建的联系规则,但它没有生成一个完整的对象,需要MazeGame的createMaze将部件组合。