您的位置:首页 > 编程语言 > Java开发

建造者模式

2015-12-20 17:43 603 查看

建造者模式

标签 : 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
的构造过程是非常复杂的(可参考
SqlSessionManager
DefaultSqlSessionFactory
实现),因此使用
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实例的产生过程

小结

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

StringBuilder
append()
;

JDBC的
PreparedStatement
;

JDOM的
DomBuilder
SAXBuilder
;

MyBatis的
SqlSessionFactoryBuilder
.

参考:

大话设计模式

《JAVA与模式》之建造模式

高淇讲设计模式

SqlSessionFactory实例的产生过程
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息