浅谈设计模式-构建者模式

书接上回,本篇讲一下创建型模式-构建者设计模式

构建者设计模式

定义:将一个复杂对象的构建与他的表示分离,使得同样的构建过程可以创建不同的表示

这定义一如既往的晦涩难懂,通读之后发现它一直在强调2个点:1>对象构建 2>对象表示,围绕这2个点,再延伸到:1>对象构建过程,2>对象的不同表示。

对象构建:简单理解就是new 对象,当实例化一个非常复杂对象时,该如何设计才能算优雅。

对象构建过程:优雅创建复杂对象实例的过程

实例:

比如使用普通new方式创建对象,

比如使用工厂模式创建对象,

比如:通过反射方式构建对象

等。

对象表示: 构建对象的具体实现步骤细节(方式)

对象不同表示:相同的构建逻辑下(这是前提),创建出不同对象表示

案例:

比如:对象属性很多, 满足某种条件,A属性有值, B属性没值,某种另外种条件,则反过来。

比如:满足某种条件,对象A方法实现A逻辑,满足另外种条件,对象A方法实现B逻辑。

上面那些概念, 如果映射到生活的例子可以这么描述: 

一条饮料全自动生产流程线,由洗瓶,配料,灌装,包装,成品区域组成,机器可以控制配料、灌装,也可以控制饮料的包装等, 同一条流水线上,根据操作选择不同, 最终饮料成品也各不相同。

一瓶饮料从空瓶到成品为:对象构建, 而整个操作过程可以理解为:对象构建过程
饮料成品生产细节(比如:如何配料,如何灌装,如何包装等):对象表示, 
不同种类的饮料生产细节:对象不同表示

案例分析

需求:使用流水线生产(需要:配料,灌装,包装 步骤)一瓶可乐

饮料-父类

//饮料父类
public class Drink {
    private String packing;    //牌子
    private String ingredient;  //配料
    private String drink;        //饮料类型

    public String getPacking() {
        return packing;
    }
    public void setPacking(String packing) {
        this.packing = packing;
    }
    public String getIngredient() {
        return ingredient;
    }
    public void setIngredient(String ingredient) {
        this.ingredient = ingredient;
    }
    public String getDrink() {
        return drink;
    }
    public void setDrink(String drink) {
        this.drink = drink;
    }
    @Override
    public String toString() {
        return "Drink{" +
                "packing='" + packing + '\'' +
                ", ingredient='" + ingredient + '\'' +
                ", drink='" + drink + '\'' +
                '}';
    }
}

可乐-子类

//可乐-饮料子类
public class Cola extends Drink{
}

生产线-接口

//生产线
public interface IBuilder {

    //配料
    IBuilder ingredientHandler(String ingredient);

    //灌装
    IBuilder fillDrink(String drink);

    //包装
    IBuilder  packing(String packing);

    //生产
    Drink build();

}

可乐生产线-接口实现

//可乐生产线
public class ColaBuilder implements IBuilder{
    private String ingredient;  //配料
    private String packing;    //瓶子的包装
    private String drink;        //饮料
    @Override
    public IBuilder ingredientHandler(String ingredient) {
        this.ingredient = ingredient;
        return this;
    }
    @Override
    public IBuilder fillDrink(String drink) {
        this.drink = drink;
        return this;
    }
    @Override
    public IBuilder packing(String packing) {
        this.packing = packing;
        return this;
    }
    @Override
    public Cola build() {
        Cola cola = new Cola();
        cola.setPacking(this.packing);
        cola.setIngredient(this.ingredient);
        cola.setDrink(this.drink);
        return cola;
    }
}

生产车间

//生产车间
public class ProductionWorkshop {

    //生产
    private IBuilder builder;

    public void setBuilder(IBuilder builder) {
        this.builder = builder;
    }
    public Drink produce(){
        return builder.build();
    }
}

测试

public class App {
    public static void main(String[] args) {
        //可乐流水线
        ColaBuilder colaBuilder = (ColaBuilder) new ColaBuilder()
                .fillDrink("百事可乐")
                .ingredientHandler("水, 糖浆,香精")
                .packing("pepsi");
        ProductionWorkshop pw = new ProductionWorkshop();
        pw.setBuilder(colaBuilder);
        Drink cola = pw.produce();
        System.out.println(cola);

    }
}

UML图

分析

结合上面的UML图,再看会构建者模式的定义:

定义:将一个复杂对象的构建与他的表示分离,使得同样的构建过程可以创建不同的表示

Cola(Drink)的创建,无非是给packing,ingredient,drink 个属性赋值,最常规的操作无非是new出对象,然后调用set方法给属性赋值。此时你就会发现, new(创建) 跟set(表现) 都在同一个Cola(Drink)中实现,也就是说对象的构建与表示是一体的。、

如果采用上面UML描述的方式设计代码, 你可以看到,最终对象是通过ProductionWorkshop.produce 方法创建而来,而对象的属性赋值通过ColaBuilder类的ingredientHandler,fillDrink ,packing 3个方法实现的。对象的构建与表示分开啦。

这就是构建者模式所表示意思。后续想生产果汁怎么办?答案是:再构建一条果汁生产线

果汁

//果汁
public class FruitJuice extends Drink{
}

果汁生产线

//果汁生产线
public class FruitJuiceBuilder implements IBuilder{
    private String ingredient;  //配料
    private String packing;    //瓶子的包装
    private String drink;        //饮料
    @Override
    public IBuilder ingredientHandler(String ingredient) {
        this.ingredient = ingredient;
        return this;
    }
    @Override
    public IBuilder fillDrink(String drink) {
        this.drink = drink;
        return this;
    }
    @Override
    public IBuilder packing(String packing) {
        this.packing = packing;
        return this;
    }
    @Override
    public FruitJuice build() {
        FruitJuice juice = new FruitJuice();
        juice.setPacking(this.packing);
        juice.setIngredient(this.ingredient);
        juice.setDrink(this.drink);
        return juice;
    }
}

 测试

public class App {
    public static void main(String[] args) {
        //可乐流水线
        ColaBuilder colaBuilder = (ColaBuilder) new ColaBuilder()
                .fillDrink("百事可乐")
                .ingredientHandler("水, 糖浆,香精")
                .packing("pepsi");
        ProductionWorkshop pw = new ProductionWorkshop();
        pw.setBuilder(colaBuilder);
        Drink cola = pw.produce();
        System.out.println(cola);


        //果汁流水线
        FruitJuiceBuilder  fruitJuiceBuilder = (FruitJuiceBuilder) new FruitJuiceBuilder()
                .fillDrink("汇源果汁")
                .ingredientHandler("水, 果汁,香精")
                .packing("hiyan");
        pw.setBuilder(fruitJuiceBuilder);
        Drink juice = pw.produce();
        System.out.println(juice);
    }
}

模式拓展

标准的构建者模式

UML图

跟案例中UML大同小异,区别是仅仅是名称

Product--产品----Drink
Builder--生成器--IBuilder
ConcreteBuilder---实际生成器---ColaBuilder
Director---指导者---ProductionWorkshop

简化版构建者模式

开发中还有一种简化版的构建者模式,就是去掉指导者:Director,实例构建直接让Builder完成即可。

回到案例代码, 直接调用builder接口中builder方法,不需要经过指导者

//可乐流水线
Drink cola =new ColaBuilder()
	.fillDrink("百事可乐")
	.ingredientHandler("水, 糖浆,香精")
	.packing("pepsi")
	.build();

实体对象内置构造器

这种方式也是一种简化方案, 将Builder设置成内部类形式

//可乐-饮料子类
public class Cola extends Drink {
    public static class ColaBuilder implements IBuilder{
        private String packing;    //牌子
        private String ingredient;  //配料
        private String drink;        //饮料类型

        @Override
        public ColaBuilder ingredientHandler(String ingredient) {
            this.ingredient = ingredient;
            return this;
        }
        @Override
        public ColaBuilder fillDrink(String drink) {
            this.drink = drink;
            return this;
        }
        @Override
        public ColaBuilder packing(String packing) {
            this.packing = packing;
            return this;
        }
        @Override
        public Cola build() {
            Cola cola = new Cola();
            cola.setPacking(this.packing);
            cola.setIngredient(this.ingredient);
            cola.setDrink(this.drink);
            return cola;
        }
    }
}

测试

public class App {
    public static void main(String[] args) {
        Cola cola = new Cola.ColaBuilder()
                .fillDrink("百事可乐")
                .ingredientHandler("水, 糖浆,香精")
                .packing("pepsi")
                .build();
        System.out.println(cola);
    }
}

小结

不管是标准的,还是简化版,内置版,只要符合对象创建与表现分离,都是构建者模式

适用场景

1>构建复杂内部构造的对象
2>想把复杂对象创建与使用分离

优缺点

优点
封装性好,创建与使用分离
扩展性好, 构建类之间相互独立,一定程度上解耦

缺点
产生多余的Builder对象
产品内部发生变化,构建者修改成本高

开发案例

案例1

还是从JDK里面找例子-StringBuilder

String--产品

StringBuilder---构建者

AbstractStringBuilder---父构建者

没有指导者

String sb = new StringBuilder()
    .append("a")
    .append("b")
    .toString();

StringBuilder 简化版的构建者模式

案例2

Spring中BeanDefinitionBuilder 也是一个简单的构建者模式

BeanDefinition--产品

BeanDefinitionBuilder ---构建者

没有父构建者

Spring容器---指导者

public final class BeanDefinitionBuilder {

    public static BeanDefinitionBuilder genericBeanDefinition() {
		return new BeanDefinitionBuilder(new GenericBeanDefinition());
	}
	public static BeanDefinitionBuilder genericBeanDefinition(Class<?> beanClass) {
		BeanDefinitionBuilder builder = new BeanDefinitionBuilder(new                         GenericBeanDefinition());
		builder.beanDefinition.setBeanClass(beanClass);
		return builder;
	}

    public AbstractBeanDefinition getBeanDefinition() {
		this.beanDefinition.validate();
		return this.beanDefinition;
	}


}

案例3

Mybatis框架中SqlSessionFactoryBuilder 是一个非常经典的构建者模式案例

SqlSessionFactory --- 产品

SqlSessionFactoryBuilder----构建者

没父构建者

客户端程序---指导者

public class SqlSessionFactoryBuilder {

  public SqlSessionFactory build(Reader reader) {
    return build(reader, null, null);
  }

  public SqlSessionFactory build(Reader reader, String environment) {
    return build(reader, environment, null);
  }

  public SqlSessionFactory build(Reader reader, Properties properties) {
    return build(reader, null, properties);
  }


  public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
    try {
      XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
      return build(parser.parse());
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error building SqlSession.", e);
    } finally {
      ErrorContext.instance().reset();
      try {
        reader.close();
      } catch (IOException e) {
        // Intentionally ignore. Prefer previous error.
      }
    }
  }

}

有意思的是, 里面还套着一个构建者模式-XMLConfigBuilder 

public class XMLConfigBuilder extends BaseBuilder {

  private boolean parsed;
  private final XPathParser parser;
  private String environment;
  private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {
    super(new Configuration());
    ErrorContext.instance().resource("SQL Mapper Configuration");
    this.configuration.setVariables(props);
    this.parsed = false;
    this.environment = environment;
    this.parser = parser;
  }
  public Configuration parse() {
    if (parsed) {
      throw new BuilderException("Each XMLConfigBuilder can only be used once.");
    }
    parsed = true;
    parseConfiguration(parser.evalNode("/configuration"));
    return configuration;
  }
}

总结

1>构建者模式的本质:分离对象构建与对象的表示。使用时前尽量结合业务实际,是否真的有这个必要,不能为了用而用。

2>构建者模式跟工厂模式主要区别在于构建对象的侧重点:构建者模式强调对象构建过程与表现结果的分离, 工厂在乎构建对象的结果。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

浪飞yes

我对钱没兴趣~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值