《设计模式》上对创建者(Builder)模式的定义是将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。相信大部分初学者都看不懂这句话。
事实上,创建者模式是一步一步创建一个复杂的对象,它允许用户可以只通过指定复杂对象的类型和内容就可以构建它们,用户不知道内部的具体构建细节。Builder模式非常类似简单工厂模式,细微的区别后面会提到。
因为一个复杂的对象,不但有很多大量组成部分,如汽车,有很多部件:车轮、方向盘、发动机还有各种小零件等等,部件很多,但远不止这些。如何将这些部件装配成一辆汽车,这个装配过程也很复杂(需要很好的组装技术),Builder模式就是为了将部件和组装过程分开。这就是构建与表示的分离。有的书上也说创建者模式是为了将构建复杂对象的过程和它的部件解耦。注意:是解耦过程和部件。创建者模式本质是将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
首先假设一个复杂对象是由多个部件组成的,Builder模式是把复杂对象的创建和部件的创建分别开来,分别用Builder接口表示部件创建,Director类来表示对象的创建。
首先,需要一个接口,它定义如何创建复杂对象的各个部件:
public interface Builder {
//创建部件A 比如创建汽车车轮
void buildPartA();
//创建部件B 比如创建汽车方向盘
void buildPartB();
//创建部件C 比如创建汽车发动机
void buildPartC();
//创建部件D 比如创建汽车车窗
void buildPartD();
//返回最后组装成品结果 (返回最后装配好的汽车)
//成品的组装过程不在这里进行,而是转移到下面的Director类中进行.
//从而实现了解耦过程和部件
Product getResult();
}
Builder接口的具体实现ConcreteBuilder类完成接口Builder来构建或装配产品的部件;定义并明确它所要创建的是什么具体东西;提供一个可以重新获取产品的接口:
package map_package;
public interface Map_interface {
public void create_weather();
public void create_house();
public void create_tree();
public void create_way();
}
public class ConcreteBuilder implements Builder {
Part partA, partB, partC;
public void buildPartA() {
//todo:这里是具体如何构建partA的代码
};
public void buildPartB() {
//todo:这里是具体如何构建partB的代码
};
public void buildPartC() {
//todo:这里是具体如何构建partC的代码
};
public void buildPartD() {
//todo:这里是具体如何构建partD的代码
};
public Product getResult() {
//返回最后组装成品结果
};
}
最后,用Director构建最后的复杂对象,而在上面Builder接口中封装的是如何创建一个个部件(复杂对象是由这些部件组成的),也就是说Director的内容是如何将部件最终组装成成品:
public class Director {
private Builder builder;
public Director( Builder builder ) {
this.builder = builder;
}
// 将部件partA partB partC等最后组成复杂对象
// 这里是将车轮 方向盘和发动机组装成汽车的过程,
// 注意,其顺序有一定的要求,比如这里必须按A->D->C->B的顺序
public void construct() {
builder.buildPartA();
builder.buildPartD();
builder.buildPartC();
builder.buildPartB();
}
}
复杂对象接口:产品Product:
public interface Product { …… }
复杂对象:
public class car implements Product { …… }
复杂对象的部件接口:
public interface Part { }
复杂对象的部件:
public class PartA implements Part { …… }
public class PartB implements Part { …… }
public class PartC implements Part { …… }
public class PartD implements Part { …… }
最后,让我们看看如何调用Builder模式:
ConcreteBuilder builder = new ConcreteBuilder();
Director director = new Director(builder);
director.construct();
Product product = builder.getResult();
我们看到,跟简单工厂最大的区别在于创建者模式并不关注对象的创建,而关注对象部件的创建,所以我们没有在Director类中找到任何new关键字。
下面,我们就通过一个例子来讲讲建造者模式的JAVA代码实现:
新建地图接口:
package map_package;
public interface map_interface {
public void create_weather();
public void create_house();
public void create_tree();
public void create_way();
}
新建晴天地图类:
package map_package;
public class map_sun implements map_interface {
public void create_weather() {
System.out.println("晴天");
}
public void create_house() {
System.out.println("房了上玻璃发亮");
}
public void create_tree() {
System.out.println("树的颜色是浅绿色");
}
public void create_way() {
System.out.println("路面有些干燥");
}
}
新建阴天地图类:
package map_package;
public class map_cloudy implements map_interface{
public void create_weather() {
System.out.println("阴天");
}
public void create_house() {
System.out.println("房了上玻璃发暗");
}
public void create_tree() {
System.out.println("树的颜色是深绿色");
}
public void create_way() {
System.out.println("路面有些潮湿");
}
}
好了,我们来看建造者模式如何封装构造过程,提升我们的代码质量,新建高画质builder建造者类:
package map_build;
import map_package.map_interface;
public class map_build_adv {
private map_interface map_interface_ref;
public map_build_adv(map_interface map_interface_ref) {
super();
this.map_interface_ref = map_interface_ref;
}
public void create_map() {
System.out.println("创建一个高画质的地图");
// 创建的顺序很重要 从天空往路面创建
map_interface_ref.create_weather();
map_interface_ref.create_house();
map_interface_ref.create_tree();
map_interface_ref.create_way();
}
}
新建低画质builder建造类:
package map_build;
import map_package.map_interface;
public class map_build_low {
private map_interface map_interface_ref;
public map_build_low(map_interface map_interface_ref) {
super();
this.map_interface_ref = map_interface_ref;
}
public void create_map() {
System.out.println("创建一个低画质的地图");
// 创建的顺序很重要 从天空往路面创建
map_interface_ref.create_weather();
map_interface_ref.create_house();
// map_interface_ref.create_tree();将创建树的过程去掉
map_interface_ref.create_way();
}
}
工作做到位了,我们就可以使用它了:
package run_main;
import map_build.map_build_adv;
import map_build.map_build_low;
import map_package.map_cloudy;
import map_package.map_sun;
public class run_main {
public static void main(String[] args) {
map_cloudy map_cloudy = new map_cloudy();
map_build_adv map_build_adv = new map_build_adv(map_cloudy);
map_build_adv.create_map();
System.out.println();
map_sun map_sun = new map_sun();
map_build_low map_build_low = new map_build_low(map_sun);
map_build_low.create_map();
}
}
程序运行结果如下:
创建一个高画质的地图
阴天
房了上玻璃发暗
树的颜色是深绿色
路面有些潮湿
创建一个低画质的地图
晴天
房了上玻璃发亮
路面有些干燥
从程序中可以看到,建造者模式将不变的创建过程进行封装,创建的过程与main分法进行分离,这样内部的创建过程就和表示层的代码进行分开,有利于创建过程功能上的修改。另外可以发现,代码的设计和功能有些类似于facade外观模式,区别在于,建造者模式目的在于以相同的构建过程通过不同的建造者得到不 同的结果,而外观模式并不需要不同的建造者,也不希望得到不同的结果,只是简单的将几个接口合并成高级的一个接口,不影响原有的结果,目的是使调用变得更加容易。
本程序中有2个建造者:高画者建造者和低画质建造者,它们都封装了创建地图的过程,这个过程很固定,但通过不同的建造者类可以返回不样式的地图,建造者规定了对象创建的过程,比如高画质的建造者的创建过程为:
map_interface_ref.create_weather();
map_interface_ref.create_house();
map_interface_ref.create_tree();
map_interface_ref.create_way();
必须得执行4个方法才可以创建一个高画质的地图,如果不使用建造者模式,直接调用map类的create_xxxx方法,如果create_xxxx方法 有几十个,那么很有可能就把其中的某些方法忘记调用而影响最终地图的效果了,所以我们要使用建造者模式来规定地图创建的过程,这就是一个“行为守则”。