1建造者模式简介
建造者模式(Builder Pattern)也叫做生成器模式,其定义如下: Separate the construction of a complex object from its representation so that the same construction process can create different representations.(将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。)
建造者模式可以将复杂对象的建造过程抽象出来(抽象类别),使这个抽象过程的不同实现方法可以构造出不同表现(属性)的对象
建造者模式是一步步创建一个复杂的对象,它允许用户只通过指定复杂对象的类型和内容就可以构建它们,用户不需要知道内部的具体构建细节
当需要实例化一个复杂的类,以得到不同结构和不同内部状态的对象时,我们可以使用不同的类对它们的实例化操作逻辑分别进行封装,这些类就被称为建造者。每当需要来自同一个类但具有不同结构的对象时,就可以通过构造另一个建造者来进行实例化。
基本类图为
该模式包含的角色有:
- Product(产品类):需要为其构建对象的类,是具有不同表现形式的复杂或复合对象。
- Builder(抽象建造者类):用于声明构建产品类的组成部分的抽象类或接口。它的作用是仅公开构建产品类的功能,隐藏产品类的其他功能;将产品类与构建产品类的更高级的类分离开。
- ConcreteBuilder(具体建造者类):用于实现抽象建造者类接口中声明的方法,构建和装配各个部件。
- Director(导演类):构建一个Builder接口的对象,它主要是用于创建一个复杂的对象。作用:①隔离调用Client类与对象的生产过程,②负责控制产品对象的生产过程
通用源码
//产品类
//通常是实现了模板方法模式
public class FastFoodClient {
public static void main(String[] args) {
//肯德基生产快餐
FastFoodDirector director1 = new FastFoodDirector();
KFCFastFoodModel kfcFastFoodModel1 = director1.getKFCFastFoodModel1();
kfcFastFoodModel1.production();
System.out.println("------------");
KFCFastFoodModel kfcFastFoodModel2 = director1.getKFCFastFoodModel2();
kfcFastFoodModel2.production();
//麦当劳生产快餐 不在演示
}
}
//抽象建造者
//规范产品的组建,一般是由子类实现
public abstract class Builder {
//设置产品的不同部分,以获得不同的产品
public abstract void setPart();
//建造产品
public abstract Product buildProduct();
}
//具体建造者
//实现抽象类定义的所有方法,并且返回一个组建好的对象
public class ConcreteProduct extends Builder {
private Product product = new Product();
//设置产品零件
public void setPart(){
/*
* 产品类内的逻辑处理
*/
}
//组建一个产品
public Product buildProduct() {
return product;
}
}
//导演类
//负责安排已有模块的顺序
public class Director {
private Builder builder = new ConcreteProduct();
//构建不同的产品
public Product getAProduct(){
builder.setPart();
/*
* 设置不同的零件,产生不同的产品
*/
return builder.buildProduct();
}
}
2传统方式
需求:快餐店生产食物,食物有饮品、汉堡包、小吃、薯条等,现在有麦当劳、肯德基、华莱士等等快餐店,各个店的食物大体相同,但是步骤不一定相同
传统方式现实快餐店生产食物需求
//产品模板类 快餐生产店
public abstract class FastFoodModel {
//饮品
protected abstract void drink();
//汉堡
protected abstract void hamburger();
//小吃
protected abstract void snack();
//薯条
protected abstract void chips();
//生产快餐
public void production(){
drink();
hamburger();
snack();
chips();
}
}
public class KFCFastFoodModel extends FastFoodModel{
@Override
protected void drink() {
System.out.println("肯德基生产饮品");
}
@Override
protected void hamburger() {
System.out.println("肯德基生产汉堡包");
}
@Override
protected void snack() {
System.out.println("肯德基生产小吃");
}
@Override
protected void chips() {
System.out.println("肯德基生产薯条");
}
}
public class MCDFastFoodModel extends FastFoodModel{
@Override
protected void drink() {
System.out.println("麦当劳生产饮品");
}
@Override
protected void hamburger() {
System.out.println("麦当劳生产汉堡包");
}
@Override
protected void snack() {
System.out.println("麦当劳生产小吃");
}
@Override
protected void chips() {
System.out.println("麦当劳生产薯条");
}
}
调用Client类
public class FastFoodClient {
public static void main(String[] args) {
//肯德基生产快餐
FastFoodModel kfcFood = new KFCFastFoodModel();
kfcFood.production();
//麦当劳生产快餐
FastFoodModel mcdFood = new MCDFastFoodModel();
mcdFood.production();
}
}
以上需求实现的弊端:当某店的食材(土豆)没有的话,就没法生产薯条,production()生产方法不够灵活,并且麦当劳和肯德基生产食材的步骤不一定相等
3建造者模式实现
根据上述代码弊端,所以为每个产品提供一个建造者的角色,想生产什么直接让建造者控制,在增加Director类,负责按照指定的顺序生产模型
//产品模板类 快餐生产店
public abstract class AbsFastFoodModel {
//定义各个基本方法执行的顺序
private ArrayList<String> sequence = new ArrayList<String>();
//饮品
protected abstract void drink();
//汉堡
protected abstract void hamburger();
//小吃
protected abstract void snack();
//薯条
protected abstract void chips();
//生产快餐
public void production(){
for (int i = 0; i < sequence.size(); i++) {
if (sequence.get(i).equals("drink")){
drink();
}else if (sequence.get(i).equals("hamburger")){
hamburger();
}else if (sequence.get(i).equals("snack")){
snack();
}else if (sequence.get(i).equals("chips")){
chips();
}
}
}
//把传递过来的值传递到类内
public void setSequence(ArrayList sequence){
this.sequence = sequence;
}
}
public class KFCFastFoodModel extends AbsFastFoodModel {
@Override
protected void drink() {
System.out.println("肯德基生产饮品");
}
@Override
protected void hamburger() {
System.out.println("肯德基生产汉堡包");
}
@Override
protected void snack() {
System.out.println("肯德基生产小吃");
}
@Override
protected void chips() {
System.out.println("肯德基生产薯条");
}
}
public class MCDFastFoodModel extends AbsFastFoodModel {
@Override
protected void drink() {
System.out.println("麦当劳生产饮品");
}
@Override
protected void hamburger() {
System.out.println("麦当劳生产汉堡包");
}
@Override
protected void snack() {
System.out.println("麦当劳生产小吃");
}
@Override
protected void chips() {
System.out.println("麦当劳生产薯条");
}
}
//构建者基类
public abstract class AbsFastFoodBuilder {
public abstract void setSequence(ArrayList sequence);//设置组装 生产顺序
public abstract AbsFastFoodModel getFastFoodModel();//获取产品类
}
public class KFCFastFoodBuilder extends AbsFastFoodBuilder{
private KFCFastFoodModel kfcFastFoodModel = new KFCFastFoodModel();
@Override
public void setSequence(ArrayList sequence) {
kfcFastFoodModel.setSequence(sequence);
}
@Override
public AbsFastFoodModel getFastFoodModel() {
return kfcFastFoodModel;
}
}
public class MDCFastFoodBuilder extends AbsFastFoodBuilder{
private MCDFastFoodModel mcdFastFoodModel = new MCDFastFoodModel();
@Override
public void setSequence(ArrayList sequence) {
mcdFastFoodModel.setSequence(sequence);
}
@Override
public AbsFastFoodModel getFastFoodModel() {
return mcdFastFoodModel;
}
}
导演类
//导演类 控制对象的生产过程
public class FastFoodDirector {
private KFCFastFoodBuilder kfcFastFoodBuilder = new KFCFastFoodBuilder();
private MDCFastFoodBuilder mdcFastFoodBuilder = new MDCFastFoodBuilder();
//该方法可以设置 生产的套餐顺序
public KFCFastFoodModel getKFCFastFoodModel1(){
ArrayList<String> sequence = new ArrayList<String>();
sequence.add("drink");
sequence.add("hamburger");
sequence.add("snack");
sequence.add("chips");
kfcFastFoodBuilder.setSequence(sequence);
return (KFCFastFoodModel) kfcFastFoodBuilder.getFastFoodModel();
}
public KFCFastFoodModel getKFCFastFoodModel2(){
ArrayList<String> sequence = new ArrayList<String>();
sequence.add("drink");
sequence.add("hamburger");
sequence.add("snack");
kfcFastFoodBuilder.setSequence(sequence);
return (KFCFastFoodModel) kfcFastFoodBuilder.getFastFoodModel();
}
public MCDFastFoodModel getMDCFastFoodBuilder1(){
ArrayList<String> sequence = new ArrayList<String>();
sequence.add("drink");
sequence.add("hamburger");
sequence.add("snack");
sequence.add("chips");
kfcFastFoodBuilder.setSequence(sequence);
return (MCDFastFoodModel) mdcFastFoodBuilder.getFastFoodModel();
}
public MCDFastFoodModel getMDCFastFoodBuilder2(){
ArrayList<String> sequence = new ArrayList<String>();
sequence.add("drink");
sequence.add("hamburger");
sequence.add("snack");
sequence.add("chips");
kfcFastFoodBuilder.setSequence(sequence);
return (MCDFastFoodModel) mdcFastFoodBuilder.getFastFoodModel();
}
}
Client类
public class FastFoodClient {
public static void main(String[] args) {
//肯德基生产快餐
FastFoodDirector director1 = new FastFoodDirector();
KFCFastFoodModel kfcFastFoodModel1 = director1.getKFCFastFoodModel1();
kfcFastFoodModel1.production();
System.out.println("------------");
KFCFastFoodModel kfcFastFoodModel2 = director1.getKFCFastFoodModel2();
kfcFastFoodModel2.production();
//麦当劳生产快餐 不在演示
}
}
注:上述代码结合了模板模式(所以代码量比较多)
总结:①封装性:使用建造者模式可以使客户端不必知道产品内部组成的细节,如例子中我们就不需要关心每一个具体的模型内部是如何实现的,产生的对象类型就是AbsFastFoodModel。
②建造者独立,容易扩展,KFCFastFoodBuilder和MDCFastFoodBuilder是相互独立的,对系统的扩展非常有利。
③具体的建造者是独立的,因此可以对建造过程逐步细化,而不对其他的模块产生任何影响
使用场景:
- 相同的方法,不同的执行顺序,产生不同的事件结果时,可以采用建造者模式。
- 多个部件或零件,都可以装配到一个对象中,但是产生的运行结果又不相同时,则可以使用该模式。
- 产品类非常复杂,或者产品类中的调用顺序不同产生了不同的效能,这个时候使用建造者模式非常合适。
建造者和工厂模式的区别:
- 都是创建型模式
- 建造者模式这是它与工厂方法模式最大不同的地方,
- 建造者模式关注的是零件类型和装配工艺(顺序),最主要的功能是基本方法的调用顺序安排,零件的装配,装配的顺序不同产生的对象也不同
- 工厂方法重点是创建,创建零件是它的主要职责,组装顺序则不是它关心的。
jdk中的StringBuilder采用了建造者模式
- Appendable接口定义了多个append抽象方法,Appendable为抽象建造者,定义了抽象方法
- AbstractStringBuilder实现了Appendable接口,充当建造者角色,只是不能实例化
- StringBuilder同时充当了导演类和具体的建造者,
- 调用api的人充当Client角色