建造者模式(Builder Pattern) 也叫做生成器模式。将一个复杂对象的构建与它的表示分离, 使得同样的构建过程可以创建不同的表示。
建造者模式的优点
●封装性
使用建造者模式可以使客户端不必知道产品内部组成的细节, 如例子中我们就不需要关心每一个具体的模型内部是如何实现的, 产生的对象类型就是CarModel。
● 建造者独立, 容易扩展
BenzBuilder和BMWBuilder是相互独立的, 对系统的扩展非常有利。
● 便于控制细节风险
由于具体的建造者是独立的, 因此可以对建造过程逐步细化, 而不对其他的模块产生任何影响。
建造者模式的使用场景
● 相同的方法, 不同的执行顺序, 产生不同的事件结果时, 可以采用建造者模式。
● 多个部件或零件, 都可以装配到一个对象中, 但是产生的运行结果又不相同时, 则可以使用该模式。
● 产品类非常复杂, 或者产品类中的调用顺序不同产生了不同的效能, 这个时候使用建造者模式非常合适。
● 在对象创建过程中会使用到系统中的一些其他对象, 这些对象在产品对象的创建过程中不易得到时, 也可以采用建造者模式封装该对象的创建过程。 该种场景只能是一个补偿方法, 因为一个对象不容易获得, 而在设计阶段竟然没有发觉, 而要通过创建者模式柔化创建过程, 本身已经违反设计的最初目标。
建造者模式的注意事项
建造者模式关注的是零件类型和装配工艺(顺序) , 这是它与工厂方法模式最大不同的地方, 虽然同为创建类模式, 但是注重点不同。大家看到这里估计就开始犯嘀咕了, 这个建造者模式和工厂模式非常相似呀, 是的, 非常相似, 但是记住一点你就可以游刃有余地使用了: 建造者模式最主要的功能是基本方法的调用顺序安排, 也就是这些基本方法已经实现了, 通俗地说就是零件的装配, 顺序不同产生的对象也不同; 而工厂方法则重点是创建, 创建零件是它的主要职责, 组装顺序则不是它关
心的。
建造者模式的扩展
建造者模式中还有一个角色没有说明, 就是零件, 建造者怎么去建造一个对象? 是零件的组装, 组装顺序不同对象效能也不同, 这才是建造者模式要表达的核心意义, 而怎么才能更好地达到这种效果呢? 引入模板方法模式是一个非常简单而有
效的办法。
建造者模式的实现方式
下面以肯德基餐厅食物和麦当劳餐厅食物为例,利用建造者模式根据不同的食品组合创建创建套餐。
PackageDirector :食物套餐组合
Food:食物
Builder: 抽象食物建造者
KFCBuilder:肯德基食物建造者
MacDonaldBuilder:麦当劳食物建造者
/**
* @Title: Builder
* @Description: 餐厅
* @author chy
* @date 2018/5/14 11:18
*/
public abstract class Builder {
/**
* 汉堡包
*/
public abstract void builderHamburger();
/**
* 可乐
*/
public abstract void builderCola();
/**
* 薯条
*/
public abstract void builderFries();
/**
* 鸡块
*/
public abstract void builderChicken();
/**
* 获取套餐信息
* @return
*/
public abstract Food getPackage();
/**
* 清理信息
* @return
*/
public abstract void clear();
}
/**
* @Title: KFCBuilder
* @Description: KFC餐厅
* @author chy
* @date 2018/5/14 11:19
*/
public class KFCBuilder extends Builder {
private Food food=new Food();
@Override
public void builderHamburger() {
food.add("肯德基汉堡包");
}
@Override
public void builderCola() {
food.add("可口可乐");
}
@Override
public void builderFries() {
food.add("肯德基薯条");
}
@Override
public void builderChicken() {
food.add("肯德基鸡块");
}
@Override
public Food getPackage() {
return food;
}
@Override
public void clear() {
food.clear();
}
}
/**
* @Title: KFCBuilder
* @Description: 麦当劳餐厅
* @author chy
* @date 2018/5/14 11:19
*/
public class MacDonaldBuilder extends Builder {
private Food food=new Food();
@Override
public void builderHamburger() {
food.add("麦当劳汉堡包");
}
@Override
public void builderCola() {
food.add("百事可乐");
}
@Override
public void builderFries() {
food.add("麦当劳薯条");
}
@Override
public void builderChicken() {
food.add("麦当劳鸡块");
}
@Override
public Food getPackage() {
return food;
}
@Override
public void clear() {
food.clear();
}
}
/**
* @Title: Food
* @Description: 食物
* @author chy
* @date 2018/5/14 11:17
*/
public class Food {
List<String> items = new ArrayList();
public void add(String part) {
items.add(part);
}
public void clear() {
items.clear();
}
public void show() {
System.out.println("套餐内容:");
for (int i = 0; i < items.size(); i++) {
System.out.println(items.get(i));
}
}
}
/**
* @Title: PackageDirector
* @Description: 组装套餐
* @author chy
* @date 2018/5/14 11:28
*/
public class PackageDirector {
/**
* 肯德基套餐A 模版
* @param kfc
*/
public void packageKFCA(Builder kfc){
kfc.clear();
kfc.builderCola();
kfc.builderChicken();
}
/**
* 肯德基套餐B 模版
* @param kfc
*/
public void packageKFCB(Builder kfc){
kfc.clear();
kfc.builderFries();
kfc.builderHamburger();
}
/**
* 麦当劳套餐A 模版
* @param mdn
*/
public void packageMDNA(Builder mdn){
mdn.clear();
mdn.builderHamburger();
mdn.builderCola();
}
/**
* 麦当劳套餐B 模版
* @param mdn
*/
public void packageMDNB(Builder mdn){
mdn.clear();
mdn.builderFries();
mdn.builderChicken();
}
}
/**
* @Title: Client
* @Description: 建造者模式: 适用于一些基本部件不会变,而其组合经常变化的场景
关键词:建造者:创建和提供实例,导演:管理建造出来的实例的依赖关系。
比如:肯德基和麦当劳 产品薯条,可乐,鸡块,汉堡 都有套餐A和套餐B
* @author chy
* @date 2018/5/14 10:51
*/
public class Client {
public static void main(String[] arg) {
//负责指挥套餐食物种类(套餐模版已经规定好食物的顺序和种类)
PackageDirector director = new PackageDirector();
//肯德基食物创建者
KFCBuilder kfc = new KFCBuilder();
//肯德基食物创建者
MacDonaldBuilder mdn = new MacDonaldBuilder();
Food food = null;
//选择肯德基A套餐
director.packageKFCA(kfc);
//组装肯德基A套餐食物
food = kfc.getPackage();
//打印食物信息
food.show();
//选择麦当劳B套餐
director.packageMDNB(mdn);
//组装麦当劳B套餐食物
food = mdn.getPackage();
//打印食物信息
food.show();
}
}