建造者模式
建造者模式
标签 : 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>
小结
- 由于构建和装配的解耦, 不同的构建器, 相同的装配过程, 可以产生不同的产品,实现了更好的复用.因此常用于创建一些复杂的对象, 这些对象内部构建间的建造顺序通常是稳定的, 但内部的构建通常面临着复杂的变化. 如:
StringBuilder
的append()
;- JDBC的
PreparedStatement
;- JDOM的
DomBuilder
、SAXBuilder
;- MyBatis的
SqlSessionFactoryBuilder
.
参考: