建造者模式

建造者模式

标签 : Java与设计模式


建造者模式: 又称生成器模式, 可以将一个产品的内部表象与产品的生成过程分割开来, 从而可以使一个建造过程生成具有不同的内部表象的产品(将一个复杂对象的构建与它的表示分离, 使得同样的构建过程可以创建不同的表示). 这样用户只需指定需要建造的类型就可以得到具体产品,而不需要了解具体的建造过程和细节.

  • 与抽象工厂的区别:
    在建造者模式中,角色分指导者(Director)建造者(Builder): 用户联系指导者, 指导者指挥建造者, 最后得到产品. 建造者模式可以强制实行一种分步骤进行的建造过程.

实现

需求: 模仿宇宙飞船的建造过程
    假设宇宙飞船有很多零部件: 引擎、轨道舱、逃逸塔、各种小零件... 因此宇宙飞船的建造/装配非常复杂(需要很好的生产/装配技术),而建造者模式可以将部件的建造与装配分开:


产品与部件

产品AirShip由多个零部件(Engine/EscapeTower/OrbitalModule)组成:

/**
 * 目标对象 - 宇宙飞船
 * (代表复杂对象, 拥有复杂的建造过程)
 * Created by jifang on 15/12/8.
 */
public class AirShip {

    private Engine engine;

    private EscapeTower escapeTower;

    private OrbitalModule orbitalModule;

    public Engine getEngine() {
        return engine;
    }

    public void setEngine(Engine engine) {
        this.engine = engine;
    }

    public EscapeTower getEscapeTower() {
        return escapeTower;
    }

    public void setEscapeTower(EscapeTower escapeTower) {
        this.escapeTower = escapeTower;
    }

    public OrbitalModule getOrbitalModule() {
        return orbitalModule;
    }

    public void setOrbitalModule(OrbitalModule orbitalModule) {
        this.orbitalModule = orbitalModule;
    }

    @Override
    public String toString() {
        return "AirShip{" +
                "engine=" + engine +
                ", escapeTower=" + escapeTower +
                ", orbitalModule=" + orbitalModule +
                '}';
    }
}

class Engine {

    private String description;

    public Engine(String description) {
        this.description = description;
    }

    @Override
    public String toString() {
        return "Engine{" +
                "description='" + description + '\'' +
                '}';
    }
}

class EscapeTower {

    private String description;

    public EscapeTower(String description) {
        this.description = description;
    }

    @Override
    public String toString() {
        return "EscapeTower{" +
                "description='" + description + '\'' +
                '}';
    }
}

class OrbitalModule {

    private String description;

    public OrbitalModule(String description) {
        this.description = description;
    }

    @Override
    public String toString() {
        return "OrbitalModule{" +
                "description='" + description + '\'' +
                '}';
    }
}

建造者(Builder)

Builder(AirShipBuilder)是为创建一个Product对象的各个部件指定的抽象接口, ConcreteBuilder(LowerAirShipBuilder/HigherAirShipBuilder)是具体的建造者, 实现Builder接口, 构造和装配各个部件.

/**
 * @author jifang
 * @since 16/8/17 下午2:13.
 */
public interface AirShipBuilder {

    void builtEngine();

    void builtEscapeTower();

    void builtOrbitalModule();

    AirShip getResult();
}

生产低端飞船, 需要LowerAirShipBuilder; 生产高端飞船, 就需要HigherAirShipBuilder:

class LowerAirShipBuilder implements AirShipBuilder {

    private AirShip airShip = new AirShip();

    @Override
    public void builtEngine() {
        System.out.println("\t\t构造低端引擎");
        airShip.setEngine(new Engine("低端 - 引擎"));
    }

    @Override
    public void builtEscapeTower() {
        System.out.println("\t\t构造低端逃逸塔");
        airShip.setEscapeTower(new EscapeTower("低端 - 逃逸塔"));
    }

    @Override
    public void builtOrbitalModule() {
        System.out.println("\t\t构造低端轨道舱");
        airShip.setOrbitalModule(new OrbitalModule("低端 - 轨道舱"));
    }

    @Override
    public AirShip getResult() {
        return airShip;
    }
}

class HigherAirShipBuilder implements AirShipBuilder {

    private AirShip airShip = new AirShip();

    @Override
    public void builtEngine() {
        System.out.println("\t\t构造高端引擎");
        airShip.setEngine(new Engine("高端 - 引擎"));
    }

    @Override
    public void builtEscapeTower() {
        System.out.println("\t\t构造高端逃逸塔");
        airShip.setEscapeTower(new EscapeTower("高端 - 逃逸塔"));
    }

    @Override
    public void builtOrbitalModule() {
        System.out.println("\t\t构造高端轨道舱");
        airShip.setOrbitalModule(new OrbitalModule("高端 - 轨道舱"));
    }

    @Override
    public AirShip getResult() {
        return airShip;
    }
}

指挥者(Director)

使用Director(AirShipDirector)控制建造过程, 也用它来隔离用户与建造过程的关联:

/**
 * @author jifang
 * @since 16/8/17 下午2:15.
 */
public class AirShipDirector {

    /**
     * 确定一种稳定的构造过程
     *
     * @param builder
     */
    public static void construct(AirShipBuilder builder) {

        builder.builtEngine();

        builder.builtEscapeTower();

        builder.builtOrbitalModule();
    }
}

Client

完全不需知道具体的创建/装配过程, 只需指定Builder:

public class Client {

    @Test
    public void client() {
        AirShipBuilder lowBuilder = new LowerAirShipBuilder();
        // 构造低端飞船
        AirShipDirector.construct(lowBuilder);
        AirShip lowShip = lowBuilder.getResult();
        System.out.println(lowShip);

        AirShipBuilder highBuilder = new HigherAirShipBuilder();
        // 相同的构造过程, 不同的Builder, 可以构造出不同的飞船
        AirShipDirector.construct(highBuilder);
        AirShip highShip = highBuilder.getResult();
        System.out.println(highShip);
    }
}

实例-MyBatis中的建造者模式

MyBatis的SqlSessionFactoryBuilder是对SqlSessionFactory建造过程的简单封装,他对建造者模式做了简化处理(只有Builder而无Director),以减小编程复杂度:

/**
 * @author Clinton Begin
 */
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.
      }
    }
  }

  public SqlSessionFactory build(InputStream inputStream) {
    return build(inputStream, null, null);
  }

  public SqlSessionFactory build(InputStream inputStream, String environment) {
    return build(inputStream, environment, null);
  }

  public SqlSessionFactory build(InputStream inputStream, Properties properties) {
    return build(inputStream, null, properties);
  }

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

  public SqlSessionFactory build(Configuration config) {
    return new DefaultSqlSessionFactory(config);
  }

}

由于SqlSessionFactory创建的SqlSession需要支持很多操作(如selectOne()selectList()update()等), 因此SqlSessionFactory的构造过程是非常复杂的(可参考SqlSessionManagerDefaultSqlSessionFactory实现),因此使用SqlSessionFactoryBuilder作为Builder简化其构造过程,并且为其设置配置文件(mybatis-configuration.xml)作为Director来指导Builder的构造过程:

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="mapperLocations" value="classpath:mybatis/mapper/*DAO.xml"/>
    <property name="typeAliases" value="com.feiqing.domain.User"/>
    <property name="configLocation" value="classpath:mybatis/mybatis-configuration.xml"/>
</bean>

详细可参考博客: mybatis源码分析(1)——SqlSessionFactory实例的产生过程


小结

  • 由于构建装配的解耦, 不同的构建器, 相同的装配过程, 可以产生不同的产品,实现了更好的复用.因此常用于创建一些复杂的对象, 这些对象内部构建间的建造顺序通常是稳定的, 但内部的构建通常面临着复杂的变化. 如:
    • StringBuilderappend();
    • JDBC的PreparedStatement;
    • JDOM的DomBuilderSAXBuilder;
    • MyBatis的SqlSessionFactoryBuilder.

参考:

  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
1) 优秀的程序应该是这样的:阅读时,感觉很优雅;新增功能时,感觉很轻松;运行时,感觉很快速,这就需要设计模式支撑。2) 设计模式包含了大量的编程思想,讲授和真正掌握并不容易,网上的设计模式课程不少,大多讲解的比较晦涩,没有真实的应用场景和框架源码支撑,学习后,只知其形,不知其神。就会造成这样结果: 知道各种设计模式,但是不知道怎么使用到真实项目。本课程针对上述问题,有针对性的进行了升级 (1) 授课方式采用 图解+框架源码分析的方式,让课程生动有趣好理解 (2) 系统全面的讲解了设计模式,包括 设计模式七大原则、UML类图-类的六大关系、23种设计模式及其分类,比如 单例模式的8种实现方式、工厂模式的3种实现方式、适配器模式的3种实现、代理模式的3种方式、深拷贝等3) 如果你想写出规范、漂亮的程序,就花时间来学习下设计模式吧课程内容和目标本课程是使用Java来讲解设计模式,考虑到设计模式比较抽象,授课采用 图解+框架源码分析的方式1) 内容包括: 设计模式七大原则(单一职责、接口隔离、依赖倒转、里氏替换、开闭原则、迪米特法则、合成复用)、UML类图(类的依赖、泛化和实现、类的关联、聚合和组合) 23种设计模式包括:创建型模式:单例模式(8种实现)、抽象工厂模式、原型模式、建造者模式、工厂模式。结构型模式:适配器模式(3种实现)、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式(3种实现)。行为型模式:模版方法模式、命令模式、访问者模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式(Interpreter模式)、状态模式、策略模式、职责链模式(责任链模式)2) 学习目标:通过学习,学员能掌握主流设计模式,规范编程风格,提高优化程序结构和效率的能力。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值