系列传送门
创建型模式
这一类模式用于创建对象。
隐藏或抽象创建对象的细节,而不是使用 new直接创建对象。
设计模式一、创建型模式-单例模式
设计模式二、创建型模式-简单工厂模式
设计模式三、创建型模式-工厂模式
设计模式四、创建型模式-抽象工厂模式
设计模式五、创建型模式-建造者模式
建造者模式
核心是把“构成对象的组件的创建过程”与“组件装配成对象的过程”分离开。
与工厂模式的区别是:建造者模式更加关注组件装配的顺序。该模式有两个角色,一个是建造者Builder,一个是导演Director。
Builder的职责是构建对象拥有的各个组件。
Director的职责是把这些组件按一定规则组合成一个对象。
下面让我们创建一张魔兽世界诺森德地图的两个区域:龙骨荒野和冰冠冰川。
定义地图对象(一张地图,有山峰、河流和建筑物)
class Map {
// 拥有的山峰
private String hill;
// 拥有的河流
private String river;
// 拥有的建筑物
private String building;
// TODO Getter and setter
@Override
public String toString() {
return "[" + hill + "," + river + "," + building + "]";
}
}
定义地图建造者接口(也可以是抽象类,定义创建各个组件(山峰,河流,建筑物)的接口和获取最终对象(地图)的接口)
public interface MapBuilder {
/**
* 创建山峰
* @param matedata 山峰的元数据,比如坐标,模型,贴图等。
* 可以使用建造者接口作为参数,同样使用建造者模式进行创建;
* 或使用抽象工厂接口作为参数,使用抽象工厂模式进行创建。
*/
void buildHill(String matedata);
/**
* 创建河流
* @param matedata 河流的元数据,比如坐标,模型,贴图等。
* 可以使用建造者接口作为参数,同样使用建造者模式进行创建;
* 或使用抽象工厂接口作为参数,使用抽象工厂模式进行创建。
*/
void buildRiver(String matedata);
/**
* 创建建筑物
* @param matedata 建筑物的元数据,比如坐标,模型,贴图等。
* 可以使用建造者接口作为参数,同样使用建造者模式进行创建;
* 或使用抽象工厂接口作为参数,使用抽象工厂模式进行创建。
*/
void buildBuilding(String matedata);
/**
* 获得构建的地图
* @return Map 构建的地图
*/
Map getMap();
}
定义地图构建的导演类(需要提供地图元数据和指定一个地图建造者)
public class MapDirector {
// 地图元数据,包含了山峰、河流和建筑物等元数据
private HashMap<String, String> mapMatedata;
// 地图建造者
private MapBuilder builder;
public MapDirector(HashMap<String, String> mapMatedata, MapBuilder builder) {
this.mapMatedata = mapMatedata;
this.builder = builder;
}
/**
* 根据提供的地图元数据,指导建造者如何使用组件构建最终地图
* @return Map 返回最终地图
*/
public Map build() {
if (mapMatedata.containsKey("Hill")) {
// 如果地图包含山峰,则创建山峰
builder.buildHill(mapMatedata.get("Hill"));
}
if (mapMatedata.containsKey("River")) {
// 如果地图包含河流,则创建河流
builder.buildRiver(mapMatedata.get("River"));
}
if (mapMatedata.containsKey("Building")) {
// 如果地图包含建筑物,则创建建筑物
builder.buildBuilding(mapMatedata.get("Building"));
}
// TODO 可以在这里配置各种规则,比如必须要有建筑物,如果没有则地图构建失败等等
// 返回由各个组件合成的地图
return builder.getMap();
}
}
定义具体的地图建造者类(MapBuilder的实现类,实现了创建组件(山峰,河流,建筑物)的接口)
下面创建龙骨荒野区域
class DragonblightMapBuilder implements MapBuilder {
// 龙骨荒野区域地图信息
private Map map;
public DragonblightMapBuilder() {
map = new Map();
}
@Override
public void buildHill(String matedata) {
// TODO 使用山峰元数据,构建山峰
// 可选,可以不实现,表示该地图不需要山峰
map.setHill(matedata);
}
@Override
public void buildRiver(String matedata) {
// TODO 使用河流元数据,构建河流
// 可选,可以不实现,表示该地图不需要河流
map.setRiver(matedata);
}
@Override
public void buildBuilding(String matedata) {
// TODO 使用建筑物元数据,构建建筑物
// 可选,可以不实现,表示该地图不需要建筑物
map.setBuilding(matedata);
}
@Override
public Map getMap() {
// 返回龙骨荒野区域地图信息
return map;
}
}
再创建冰冠冰川区域
class IcecrownGlacierMapBuilder implements MapBuilder {
// 冰冠冰川区域地图信息
private Map map;
public IcecrownGlacierMapBuilder() {
map = new Map();
}
@Override
public void buildHill(String matedata) {
// TODO 使用山峰元数据,构建山峰
// 可选,可以不实现,表示该地图不需要山峰
map.setHill(matedata);
}
@Override
public void buildRiver(String matedata) {
// TODO 使用河流元数据,构建河流
// 可选,可以不实现,表示该地图不需要河流
map.setRiver(matedata);
}
@Override
public void buildBuilding(String matedata) {
// TODO 使用建筑物元数据,构建建筑物
// 可选,可以不实现,表示该地图不需要建筑物
map.setBuilding(matedata);
}
@Override
public Map getMap() {
// 返回冰冠冰川区域地图信息
return map;
}
}
测试
public class Main {
/**
* 建造者模式:
* 核心是把“构成对象的组件的创建过程”与“组件装配成对象的过程”分离开。
* 与工厂模式的区别是:建造者模式更加关注组件装配的顺序。
* <p>
* 该模式有两个角色,一个是建造者Builder,一个是导演Director。
* Builder的职责是构建对象拥有的各个组件。
* Director的职责是把这些组件按一定规则组合成一个对象。
*/
public static void main(String[] args) {
// 创建诺森德地图的龙骨荒野区域
HashMap<String, String> dragonblightMapData = new HashMap<>();
// 有山峰
dragonblightMapData.put("Hill", "巨大的龙骨");
// 没有河流
// 有建筑物
dragonblightMapData.put("Building", "龙眠神殿");
Map dragonblightMap = new MapDirector(dragonblightMapData, new DragonblightMapBuilder()).build();
// 龙骨荒野区域地图:[巨大的龙骨,null,龙眠神殿]
System.out.println("龙骨荒野区域地图:" + dragonblightMap.toString());
// 创建诺森德地图的冰冠冰川区域
HashMap<String, String> icecrownGlacierMapData = new HashMap<>();
// 没有山峰
// 有河流
icecrownGlacierMapData.put("River", "一大片的冰川");
// 有建筑物
icecrownGlacierMapData.put("Building", "巨大的冰塔");
Map icecrownGlacierMap = new MapDirector(icecrownGlacierMapData, new IcecrownGlacierMapBuilder()).build();
// 冰冠冰川区域地图:[null,一大片的冰川,巨大的冰塔]
System.out.println("冰冠冰川区域地图:" + icecrownGlacierMap.toString());
}
}