建造者模式及应用举例

目录

  • 模式名和分类
  • 意图
  • 动机
  • 适用性
  • 结构
  • 参与者
  • 协作
  • 效果
  • 代码实例
  • 已知应用
  • 总结

模式名和分类

builder
创建型模式

意图

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

将对象的创建过程细化并固化,能依此创建一个流水线,在流水线上组装对象的各个零件,最终生成我们想要的对象

动机

spring创建对象时,我们在解析xml文件和一些系统配置来创建一个的BeanDefinition,解析过程是复杂且多样的。
如果准备好所有的参数,并在new的时候直接赋值进去,难免会让创建对象这个动作显得臃肿且难看。
我们的想法是解析一些元素,处理一些元素,就将他设置到“待创建的对象中”,就像流水线一样,做好一个零件就安装一个零件,知道最后流水线走完,所有零件都到位,就能得到一个完整的对象。
总之:由于bean的复杂性,我们想细化这个过程,更完美的控制它的创建。

适用性

  • 如果你现在创建对象需要传入很多参数,又不想在构造函数中传入太多参数,使得代码难以阅读。
  • 如果你创建的对象非常的复杂,里面的很多细节或者属性需要不断的处理,而你想处理完一个组件就能毫无顾忌的处理下一个,而不用担心会忘记或者混乱已经处理好的模块。

结构

参与者

  • ProductBuilder:产品建造师。它负责创建产品
  • Product:声明父类,表明有多种产品,每种产品都有partA和partB,但是不同的产品的partA和partB有不同的实现细节
  • ProductXX、ProductYY:产品XX和YY,拥有自己的partA和partB实现方式。

协作

  • builder中聚合了Product。在构造函数中传入具体产品,例如要创建ProductXX,在构造函数中传入ProductXX.class(只要能确定具体产品,什么形式都行),表明要创建ProductXX。
  • 创建partA,已经知道了我们要创建ProductXX,那么setPartA,就设置属于ProductXX的partA。
  • 创建partB,已经知道了我们要创建ProductXX,那么setPartB,就设置属于ProductXX的partB。

效果

  • 我们支持创建不同的产品。
  • 我们可以根据需要为每个产品设置不同的值,或者不同的操作。
  • 我们可以一一设置产品的属性,而不需要在构造函数中统一传入,如果属性很多,那岂不是在构造函数中要传入一大串参数....看到看不了。

代码实例

例1、模式代码

// 步骤1 创建产品簇
public abstract class AbstractProduct {
    protected String name;
    protected String partA;
    protected String partB;

    AbstractProduct(String name){
        this.name = name;
    }

    public String getPartA() {
        return partA;
    }

    public void setPartA(String partA) {
        this.partA = partA;
    }
    public void setPartB(String partB) {
        this.partB = partB;
    }

    public String toString(){
        return "name:"+name+", partA:"+partA+", partB:"+partB;
    }
}

public class ProductXX extends AbstractProduct{
    public ProductXX(String name){
        super(name);
    }
}

public class ProductYY extends AbstractProduct{
    public ProductYY(String name){
        super(name);
    }
}

// 步骤2 创建建造者,建造师...
// 他来创建产品的细节...
public class ProductBuilder {
    private final AbstractProduct product;

    public ProductBuilder(AbstractProduct product) {
        this.product = product;
    }

    // 设置partA
    public AbstractProduct setPartA(String partA){
        this.product.setPartA(partA);
        return this.product;
    }

    // 设置partB
    public AbstractProduct setPartB(String partB){
        this.product.setPartB(partB);
        return this.product;
    }

    public AbstractProduct getProduct(){
        this.check();
        return product;
    }

    /**
     * 这个方法用来校验product的关键信息是否全部设置完成。
     * @param
     * @author caodahuan
     * @date 2019/8/21
     * @return void
     */
    private void check() {
        // todo
    }
}

// 步骤3,重点!如何使用建造者帮我们建造
public class Director {
    private ProductBuilder builder;

    public Director(ProductBuilder builder) {
        this.builder = builder;
    }

    public AbstractProduct getProduct(){
        builder.setPartA("零件A");
        builder.setPartB("零件B");
        return builder.getProduct();
    }
}

// 测试
public class TestMain {
    public static void main(String[] args) {
        Director director = new Director(new ProductBuilder(new ProductXX("产品XX")));
        AbstractProduct product = director.getProduct();
        System.out.println(product.toString());

        director = new Director(new ProductBuilder(new ProductXX("产品YY")));
        product = director.getProduct();
        System.out.println(product.toString());
    }
}

?? ?

已知应用

  • 工厂流水线
  • spring中对于建造者的使用

    spring框架,主要是用来管理对象,创建一个对象是极其复杂的,建造者模式在解析xml文件,创建BeanDefiniton中发挥很大的作用。不想在这里做更细节的分析,但是可以找段代码,分析spring是如何使用它

  • 段落1:spring-security中解析xml
private BeanReference registerMethodSecurityInterceptor(ParserContext pc,
??????String authMgrRef, String accessManagerId, String runAsManagerId,
??????BeanReference metadataSource,
??????List<BeanMetadataElement> afterInvocationProviders, Object source,
??????boolean useAspectJ) {
? ? //?建造者:建造方法拦截器beanDefinition,如果开启切面,则使用AspectJMethodSecurityInterceptor,若没有开启切面,则使用MethodSecurityInterceptor
???BeanDefinitionBuilder bldr = BeanDefinitionBuilder
?????????.rootBeanDefinition(useAspectJ ? AspectJMethodSecurityInterceptor.class
???????????????: MethodSecurityInterceptor.class);
? ? //?建造者:添加资源
???bldr.getRawBeanDefinition().setSource(source);
? ? //?建造者:添加“决策(放行)管理器”
???bldr.addPropertyReference("accessDecisionManager", accessManagerId);
? ? //?建造者:定义“鉴权管理器”BeanDefinition
???RootBeanDefinition authMgr = new RootBeanDefinition(
?????????AuthenticationManagerDelegator.class);
? ? //?建造者:将自定义“鉴权管理实现”注入到鉴权管理BeanDifinition
???authMgr.getConstructorArgumentValues().addGenericArgumentValue(authMgrRef);
???bldr.addPropertyValue("authenticationManager", authMgr);
? ? //?安全相关数据源BeanReference
???bldr.addPropertyValue("securityMetadataSource", metadataSource);

? ? //?建造者:如果拥有赋权,也将添加到beanDefinition中
???if (StringUtils.hasText(runAsManagerId)) {
??????bldr.addPropertyReference("runAsManager", runAsManagerId);
???}

? ? //?如果自定义了处理器,也要为处理器制作一个BeanDefinition,这里使用RootBeanDefinition是在2.5以前的做法,表示作为根BeanDefinition.
? ? //?对应的还有childBeanDefinition,RootBeanDefinition / ChildBeanDefinition用来预定义具有parent/child关系的bean definition。
? ? //?所以RootBeanDefinition是一个可合并的BeanDefinition?
???if (!afterInvocationProviders.isEmpty()) {
??????BeanDefinition afterInvocationManager;
??????afterInvocationManager = new RootBeanDefinition(
????????????AfterInvocationProviderManager.class);
??????afterInvocationManager.getPropertyValues().addPropertyValue("providers",
????????????afterInvocationProviders);
? ? //?建造者:然后将只做好的处理器beanDefinition添加到方法拦截器的beanDefinition中
??????bldr.addPropertyValue("afterInvocationManager", afterInvocationManager);
???}

? ? //?建造者:在建造师处理好之后获取最终的BeanDefinition
???BeanDefinition bean = bldr.getBeanDefinition();
???String id = pc.getReaderContext().generateBeanName(bean);
???pc.registerBeanComponent(new BeanComponentDefinition(bean, id));

???return new RuntimeBeanReference(id);
}

//关于切面的支持
// 如果打开了切面支持,则要为增强切面添加BeanDefinition
???if (useAspectJ) {
??????BeanDefinitionBuilder aspect = BeanDefinitionBuilder
????????????.rootBeanDefinition("org.springframework.security.access.intercept.aspectj.aspect.AnnotationSecurityAspect");
??????aspect.setFactoryMethod("aspectOf");
??????aspect.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
??????aspect.addPropertyValue("securityInterceptor", interceptor);
??????String id = pc.getReaderContext().registerWithGeneratedName(
????????????aspect.getBeanDefinition());
??????pc.registerBeanComponent(new BeanComponentDefinition(aspect
????????????.getBeanDefinition(), id));
???}
????// 如果需要,增加动态代理处理器
???else {
??????registerAdvisor(pc, interceptor, metadataSource, source,
????????????element.getAttribute(ATT_ADVICE_ORDER));
??????AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(pc, element);
???}
  • 段落2:spring中关于解析自定义标签生成BeanDefinition。(在模板模式笔记中,曾引用过这段,builder在spring中应用广泛)
// 这个定义在AbstractSingleBeanDefinitionParser中,是我们自定义解析器的父类。
@Override
protected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
? ? // 建造者:获取建造者,建造的对象是:GenericBeanDefinition

    //在执行我们自定义的解析器中的方法之前,先执行一些准备工作,也可以叫做预解析,对beanClass、scope、lazyInit等属性的准备
???BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
???String parentName = getParentName(element);
???if (parentName != null) {
??????builder.getRawBeanDefinition().setParentName(parentName);
???}
? ? // 这个是自定义解析器中重写的getBeanClass方法
???Class<?> beanClass = getBeanClass(element);
???if (beanClass != null) {
    // 建造者:我们取得了beanClass,它将作为对象的零件,先‘安装’在对象上
??????builder.getRawBeanDefinition().setBeanClass(beanClass);
???}
???else {
?? ?? ? // 如果没有重写getBeanClass方法,就看有没有重写getBeanClassName方法;
??????String beanClassName = getBeanClassName(element);
??????if (beanClassName != null) {
      //  建造者:如果取得了beanClassName,‘安装’在对象上
?????????builder.getRawBeanDefinition().setBeanClassName(beanClassName);
??????}
???}
   // 建造者:安装其他零件
???builder.getRawBeanDefinition().setSource(parserContext.extractSource(element));
???BeanDefinition containingBd = parserContext.getContainingBeanDefinition();
???if (containingBd != null) {
? ??? ? //如果存在父类,就使用父类的scope属性
??????// Inner bean definition must receive same scope as containing bean.
??????builder.setScope(containingBd.getScope());
???}
???if (parserContext.isDefaultLazyInit()) {
?? ?? ? //  建造者:安装‘零件’懒加载方式。设为延迟懒加载
??????// Default-lazy-init applies to custom bean definitions as well.
??????builder.setLazyInit(true);
???}
? ? // 模板模式:doParse被我们自定义的解析器重写;实现模板模式。
???doParse(element, parserContext, builder);
   //  建造者:获取最终的BeanDefiniton对象(最开始的GenericBeanDefinition)。
???return builder.getBeanDefinition();
}

总结

先保持一个思想:建造者模式很简单。
其次:建造者模式很灵活,如果能解读框架源码,会发现在创建对象这个功能上,建造者模式应用非常广。
最后:以上可能不能完全描述建造者的精髓,本人很看重这个模式。查看结构图,我们其实可以做很多的扩展:

  • builder也可以配合继承体系,制作更细节的建造者
  • 产品体系(被建造者体系),也可以很灵活,要注意哪些是放在流水线上的零件,哪些是归属于自己独有的零件。

原文地址:https://www.cnblogs.com/dhcao/p/11393459.html

时间: 2024-10-21 01:14:59

建造者模式及应用举例的相关文章

Java设计模式学习笔记,三:建造者模式

建造者模式:实现了构建和装配的解耦,即对象的各个子组件单独构建,再进行装配,从而建造完整对象. 该模式适用于构建较为复杂的对象(多个子组件). 不同的构建者,使用相同的装配者,可以建造不同的对象实例.相同的构建者,不同的装配顺序,也可能建造出不同的对象实例. 举例: 汽车对象,子组件包括引擎.轮子和车体. Audi汽车构建者,负责制造Audi牌各个子组件.BMW汽车构建者,负责制造BMW牌各个子组件.然后将子组件统一送至汽车装配者的生产线中进行组装,最后会建造出Audi牌汽车和BMW汽车. 以下

设计模式学习-建造者模式

1.定义 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示. 2.类图 3.代码示例 1 package com.zhaoyangwoo.builder; 2 3 /** 4 * Created by john on 16/5/7. 5 * 场景类 6 */ 7 public class Builder { 8 9 public static void Main(){ 10 BuilderInterface bi = new ConceptBuilder(); 11 Di

设计模式【建造者模式】

概述: 将一个复杂的构建与它的表示分离,使得同样的构建过程可以创建不同的表示. [拓展] 与抽象工厂的区别:在建造者模式里,有个指导者,由指导者来管理建造者,用户是与指导者联系的,指导者联系建造者,最后得到产品.即建造模式可以强制实行一种分步骤进行的建造过程. [转载使用,请注明出处:http://blog.csdn.net/mahoking] 适用性: 1. 当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时: 2. 当构建过程必须允许被构建的对象有不同的表示时. 参与者: 1

第4章 建造者模式(Builder Pattern)

原文 第4章 建造者模式(Builder Pattern) 定义 将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示,这样的设计模式被称为建造者模式. 实用范围 1 当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时. 2 当构造过程必须允许被构造的对象有不同表示时. 角色 在这样的设计模式中,有以下几个角色: 1 builder:为创建一个产品对象的各个部件指定抽象接口. 2 ConcreteBuilder:实现Builder的接口以构造和装配该产品的各个部

【设计模式与Android】建造者模式——建军大业

什么是建造者模式 所谓建造者模式,就是将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示的设计模式.建造者模式在构建过程中隐藏了复杂的实现细节,可以大大降低代码耦合度. 建造者模式的实现方式   <水浒传>讲述了的故事,梁山泊是一个不断壮大的队伍 先写一个Troops: public abstract class Troops { protected String leader;    protected ArrayList<String> others =

设计模式之————建造者模式

建造者模式 1. 什么是建造者模式? 建造者模式属于创造型模式,它是将复杂对象的建造过程抽象出来,使这个抽象过程的不同实现方法可以构造出不同表现的对象. 举例: 普通房子和高楼,两者都很难建造,但也有相似点:打地基.砌墙.盖屋顶. 普通房子的地基5m,墙10cm:高楼的地基100m,墙20cm. 2. 建造者模式结构 Product(产品角色):一个具体的产品对象 Builder(抽象建造者):创建一个Product对象的各个部件指定的接口/抽象类 ConcreteBuilder(具体建造者):

设计模式之美学习-设计模式-建造者模式(十起)

需求 我们需要定义一个资源池配置类 ResourcePoolConfig.这里的资源池,你可以简单理解为线程池.连接池.对象池等.在这个资源池配置类中,有以下几个成员变量,也就是可配置项.现在,请你编写代码实现这个 ResourcePoolConfig 类. 实现方式一 实现 public class ResourcePoolConfig { private static final int DEFAULT_MAX_TOTAL = 8; private static final int DEFA

【2016-10-16】【坚持学习】【Day7】【建造者模式】

建造者模式: 一个复杂的对象由多个分部件组成.一个复杂对象 class Product { private string partA; //定义部件,部件可以是任意类型,包括值类型和引用类型 private string partB; private string partC; public string PartA { get { return partA; } set { partA = value; } } public string PartB { get { return partB;

设计模式那点事读书笔记(3)----建造者模式

建造者模式: 建造者模式是将复杂的对象构造进行分离,使得每个部件完成比较独立的工作.通过抽象类,接口来约束建造的过程. 解决什么问题: 当生成的产品对象内部具有复杂的结构. 当复杂对象需要与表示分离,可能需要创建不同的表示时. 当需要向客户隐藏产品内部结构表现时. UML: 代码结构: 商品的实体: package com.demo.builder.model; /** * 产品实体 */ public class MobilePackage { private float money; pri