码迷,mamicode.com
首页 > 其他好文 > 详细

建造者模式

时间:2015-12-20 19:32:51      阅读:258      评论:0      收藏:0      [点我收藏+]

标签:

建造者模式

标签: Java与设计模式


访问控制符拾忆

从C++转过来的同学要注意一下了, Java比C++多了包的概念, 因此在权限访问符中也多了一个包访问级别(default:不写访问控制符, 默认default).

* private default protected public
类内 + + + +
包内 + + +
子类 + +
全局 +

注意:

  • 子类访问权限要比包访问权限要更严格(需要的权限更大).
  • 外部类只有两种访问权限: publicdefault.
  • 如果某个类只用作其他类的父类, 该类里包含的大部分方法仅仅希望被子类重写, 而不想被外界直接调用, 则应该使用protected修饰这些方法.

Java Bean规范:
  如果一个Java类每个实例变量都被private修饰, 并为每个实例变量都提供getter/setter方法, 那么这个类就是一个符合JavaBean规范的类.


建造者模式

建造者模式: 将一个复杂对象的构建与它的表示分离, 使得同样的构建过程可以创建不同的表示(将一个产品的内部表示与产品的生成过程分割开来);

  • 建造者模式与抽象工厂的区别:
      在建造者模式里,有个指导者(Director),由指导者来管理建造者(Builder),用户是与指导者联系的,指导者联系建造者最后得到产品。即建造模式可以强制实行一种分步骤进行的建造过程.
      如果我们使用了建造者模式,那么用户只需指定需要建造的类型就可以得到他们, 而具体的建造过程和细节就不要关心了.
      举个简单的例子,如宇宙飞船,有很多部件: 引擎, 轨道舱, 逃生塔,还有各种小零件等等,如何将这些部件装配成一艘宇宙飞船,这个装配过程非常复杂(需要很好的组装技术), Builder模式就是为了将部件和组装分开.
    技术分享

  • Product
    产品类, 由多个部件组成(假设我们这艘宇宙飞船的建造过程非常复杂)

/**
 * 目标对象 - 宇宙飞船
 * (代表复杂对象, 拥有复杂的建造过程)
 * 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;
    }
}

class Engine {
    private String description;

    public Engine() {
    }

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

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }
}

class EscapeTower {
    private String description;

    public EscapeTower() {
    }

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

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }
}

class OrbitalModule {
    private String description;

    public OrbitalModule() {
    }

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

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }
}
  • 建造者(Builder)
    • 确定产品有N个部件(本例中是引擎, 逃逸塔, 轨道舱)组成, 并声明一个得到最终产品的方法.
public interface AirShipBuilder {

    Engine builtEngine();

    EscapeTower builtEscapeTower();

    OrbitalModule builtOrbitalModule();

    AirShip getProduct(AirShipDirector director);
}

然后我们需要创建一个低端的宇宙飞船, 让这个宇宙飞船的建造者实现这个接口

public class LowAirShipBuilder implements AirShipBuilder {

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

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

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

    @Override
    public AirShip getProduct(AirShipDirector director) {
        AirShip airShip = new AirShip();
        director.directAirShip(airShip);
        return airShip;
    }
}
  • 指挥者(Director)
    我么使用Director来控制建造过程, 也用它来隔离用户与建造过程的关联
public abstract class AirShipDirector {

    protected AirShipBuilder builder;

    public AirShipDirector(AirShipBuilder builder){
        this.builder = builder;
    }

    public abstract void directAirShip(AirShip airShip);
}

此时, 这艘宇宙飞船的构造过程就完全由Director的子类来确定了(是先构造引擎还是先构造逃逸塔)

public class LowAirShipDirector extends AirShipDirector {

    public LowAirShipDirector(AirShipBuilder builder) {
        super(builder);
    }

    @Override
    public void directAirShip(AirShip airShip) {
        airShip.setEngine(builder.builtEngine());
        airShip.setEscapeTower(builder.builtEscapeTower());
        airShip.setOrbitalModule(builder.builtOrbitalModule());
    }
}
  • Client
    客户完全不需知道具体的建造过程
/**
 * Created by jifang on 15/12/8.
 */
public class Client {

    @Test
    public void client() {
        AirShipBuilder builder = new LowAirShipBuilder();
        // 由Director来指导AirShip的构造过程
        AirShip airShip = builder.getProduct(new LowAirShipDirector(builder));
        System.out.println(airShip.getEngine().getDescription());
        System.out.println(airShip.getEscapeTower().getDescription());
        System.out.println(airShip.getOrbitalModule().getDescription());
    }
}

建造者模式的本质:
- 分离了对象子模块单独构造(由Builder负责)和装配(有Director负责)过程. 从而可以构造出复杂的对象.
- 由于实现了构建和装配的解耦. 不同的构建器, 相同的装配, 可以做出不同的对象, 反之亦然. 也就是实现了构建算法装配算法的解耦, 实现了更好的复用;

开发中应用场景:
  建造者模式适用于建造的目标对象十分庞大, 比如像宇宙飞船, iPhone手机, 涉及的组件非常多, 建造过程复杂的情况.

  • StringBuilder类的append方法;
  • JDBC中的PreparedStatement;
  • JDOM中, DomBuilder, SAXBuilder;
  • MyBatis中的SqlSessionFactoryBuilder;

SqlSessionFactoryBuilder中的建造者模式

  SqlSessionFactoryBuilder其实对建造者模式做了简化处理(因为其只有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的构造是很复杂的(细节请参考下面的xml代码), 因此, MyBatis为他做了一个Builder, 我们可以为该类传进一个配置文件来构造SqlSessionFactory(其实, 这个配置文件我们可以认为是一个Director).

<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>

由此, 我们可以看到Builder模式是如何用到MyBatis中的.


参考:

建造者模式

标签:

原文地址:http://blog.csdn.net/zjf280441589/article/details/50364975

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!