有时候我们构造一个对象的时候,直接所需的参数未必都已经准备好,需要分步骤收集,或者需要在现有的参数上再做判断和进一步处理,又或者需要用户临时去决定。简而言之,我们只有间接数据,没有直接数据,因此不能简单地构造对象。如果将这些步骤逻辑或处理逻辑加入到构造函数,会使类构造函数变得复杂,类职责也不够单一。
Builder模式的意图是,将复杂的构建逻辑从目标类的构造函数中移除。
Builder模式最常用于解析配置文件以产生一个与配置文件对应的配置对象的情形。一开始,我们只有一个XML文件,参数都是未准备好的,需要在解析过程中逐步产生并且记录下来。引入Builder模式,解析过程中产生的数据可以先写到中间对象Builder中去,完全准备好后,再调用Builder对象的build方法,返回配置对象。build方法还可以有一些校验和处理的逻辑,确保返回的目标对象合法。这样,与具体业务相关的构建逻辑就完全集中在Builder和Parser中去,配置类的构造函数只有基本的赋值逻辑。
Builder模式基本工作过程如下
1 生成并保存直接数据到Builder对象中;
2 处理和校验直接数据;
3 将直接数据传入目标类简单的构造函数,生成目标对象。
1,2,3步骤都可以直接写到Builder.build方法里面,也可以分开,视乎实际情况,总之,我们的目标是将复杂的构建逻辑从目标类的构造函数中移除,具体实现方式可以很灵活。Builder模式的核心思想是单一职责,类构建逻辑与类核心功能应该分开。
例子1
例子2
mybatis的session工厂类org.apache.ibatis.session.SqlSessionFactory与session工厂构造类org.apache.ibatis.session.SqlSessionFactoryBuilder
对于DefaultSqlSessionFactory,我们是无法直接准备好Configuration的,需要对配置文件进行解析才能得到Configuration。我们可以将解析逻辑直接写到DefaultSqlSessionFactory,那样的话,DefaultSqlSessionFactory会多出许多个构造函数,而且引入了与SqlSessionFactory本身毫无关系的XMLConfigBuilder。这样的方式,违反了单一职责,可读性也降低了。读者看一个类,通常只会关注这个类能干什么,而不是怎么创建出来的,类构建逻辑与核心功能逻辑写在一起,集中了太多的代码,会分散读者的注意力。复杂而且与类作用无重大关系的构建逻辑应该单独分开,让类的职责更加简明。
为了将构建逻辑从目标类中移除出去,mybatis使用了Builder模式。SqlSessionFactoryBuilder类的build方法接收Reader,Envrioment,Properties等参数,解析出Configuration对象,并最终调用DefaultSqlSessionFactory的构造函数返回一个SqlSessionFactory对象。我们可以看到,DefaultSqlSessionFactory类只有自身核心功能的代码,干净,易读。
package org.apache.ibatis.session.defaults; import org.apache.ibatis.exceptions.ExceptionFactory; import org.apache.ibatis.executor.Executor; import org.apache.ibatis.executor.ErrorContext; import org.apache.ibatis.logging.Log; import org.apache.ibatis.logging.LogFactory; import org.apache.ibatis.logging.jdbc.ConnectionLogger; import org.apache.ibatis.mapping.Environment; import org.apache.ibatis.session.*; import org.apache.ibatis.transaction.Transaction; import org.apache.ibatis.transaction.TransactionFactory; import org.apache.ibatis.transaction.managed.ManagedTransactionFactory; import javax.sql.DataSource; import java.sql.Connection; import java.sql.SQLException; public class DefaultSqlSessionFactory implements SqlSessionFactory { private static final Log log = LogFactory.getLog(Connection.class); private final Configuration configuration; private final TransactionFactory managedTransactionFactory; public DefaultSqlSessionFactory(Configuration configuration) { this.configuration = configuration; this.managedTransactionFactory = new ManagedTransactionFactory(); } public SqlSession openSession() { } public SqlSession openSession(boolean autoCommit) { } public SqlSession openSession(ExecutorType execType) { } public SqlSession openSession(TransactionIsolationLevel level) { } public SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level) { } public SqlSession openSession(ExecutorType execType, boolean autoCommit) { } public SqlSession openSession(Connection connection) { } public SqlSession openSession(ExecutorType execType, Connection connection) { } public Configuration getConfiguration() { } private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) { } private SqlSession openSessionFromConnection(ExecutorType execType, Connection connection) { } private DataSource getDataSourceFromEnvironment(Environment environment) { } private TransactionFactory getTransactionFactoryFromEnvironment(Environment environment) { } }
package org.apache.ibatis.session; import org.apache.ibatis.builder.xml.XMLConfigBuilder; import org.apache.ibatis.exceptions.ExceptionFactory; import org.apache.ibatis.session.defaults.DefaultSqlSessionFactory; import org.apache.ibatis.executor.ErrorContext; import java.io.IOException; import java.io.Reader; import java.util.Properties; 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 props) { try { XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, props); Configuration config = parser.parse(); return build(config); } 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(Configuration config) { return new DefaultSqlSessionFactory(config); } }
利与弊
也许有人觉得这太折腾了,一个类变两个类。设计模式就是这样东西,你完全可以认为它没有必要,甚至有时候觉得它把问题复杂化。设计模式与其说是一种规范一种标准,不如说是一种思考和抽象的哲学。有人觉得类职责足够小是好的,但也有人觉得一个大而全的类是好的。不过对于使用类的人员,小而简单的类显然更容易接受。从目前软件的状况来看,更多人倾向于“小”。为了让东西变小,通常采取的方式是隐藏或者移除对外无太大用处的信息,这样至少表面上会让外界看起来很简单,虽然实质的内涵还是一样的复杂。
用不用设计模式,没有绝对的好与坏,更没有对与错,我们需要做的是取其精华,去其糟粕。builder模式带来了一些缺点
1 类从一个变成两个
2 维护人员需要学习设计模式
,但是也带来了足够大的优点:
1 职责分明,创建逻辑与核心功能分开,程序逻辑更清晰,层级更分明
2 对于类使用人员,注意力集中到类的核心功能上,感觉轻松了
3 对于类维护人员,可以用不同的builder类或者方法来实现不同的创建逻辑,灵活可扩展
相关推荐
Builder模式是一种创建型设计模式,它提供了一种方法来分步骤构建复杂的对象,使得构建过程和表示分离。这种模式在程序开发中常用于构造产品对象,尤其是当对象的构造过程较为复杂时,Builder模式能够帮助我们更好地...
Builder模式是一种创建型设计模式,它提供了一种创建对象的抽象接口,并允许子类按照步骤构建复杂的对象。这种模式将对象的创建过程分离出来,使得同样的构造过程可以创建不同的表示,从而实现对象创建过程的解耦。 ...
Builder模式 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示 统设计中,有时候面临着一个“复杂系统”的创建工作,该对象通常由各个部分的子对象用一定的算法构成,或者说按一定的...
Builder模式是一种设计模式,它属于创建型模式,主要用于构建复杂对象。这种模式允许我们通过分离对象的构造过程和表示来创建对象,使得构造过程可以更加灵活,并且能够避免在构造过程中对对象状态的直接修改。...
在设计模式中对Builder模式的定义是用于构建复杂对象的一种模式,所构建的对象往往需要多步初始化或赋值才能完成。那么,在实际的开发过程中,我们哪些地方适合用到Builder模式呢?其中使用Builder模式来替代多参数...
【Java面试题】builder模式
Builder模式是一种设计模式,它属于创建型模式,主要用于复杂对象的构建。在C++中,Builder模式可以帮助我们分步骤地创建一个复杂的对象,而无需关注这些步骤如何组合在一起。这样可以使得构造过程更加灵活,同时也...
Builder模式是一种创建型设计模式,它提供了一种创建对象的灵活方式,将对象的构建过程与表示分离。这种模式在复杂对象的构造过程中特别有用,因为它允许我们通过不同的步骤来构造对象,而不会让客户端代码受到这些...
Builder模式是一种设计模式,主要目的是将复杂对象的构建与表示分离,使得构建过程可以独立于表示进行。在软件工程中,当需要创建的对象具有多个可变组成部分时,Builder模式能够帮助我们构造这些对象,同时保持构建...
**建造者模式(Builder Pattern)**是软件设计模式中的一种,属于创建型模式。它将复杂对象的构建过程与它的表示分离,使得同样的构建过程可以创建不同的表示。建造者模式通常用于那些需要大量构造参数的对象,通过...
在Java或者其他面向对象编程语言中,Builder模式经常被用来提高代码的可读性和可维护性。 Builder模式的核心包括四个角色:Product(产品类)、ConcreteBuilder(具体建造者)、Builder(抽象建造者)和Director...
Builder模式是一种设计模式,主要用来创建复杂对象,它将对象的构建与表示分离,使得同样的构建过程可以创建不同的表示。在Android开发中,Builder模式被广泛应用于创建视图或者复杂的对象配置,例如Intent的构造...
在 Java 开发中,Builder 模式是一种强大的创建型模式,它允许我们逐步构建复杂的对象。本文将详细介绍 Builder 模式的意图、解释、编程示例、适用场景以及实际应用。同时,还将提供示例代码的下载链接,方便读者...
Java Builder模式是一种设计模式,它在对象构建过程中提供了一种灵活的方式来组合对象的各个部分,使得代码更加清晰、易于维护。在"Java Builder 模式之贷款办理"这个主题中,我们可以深入理解如何利用Builder模式来...
Builder模式是一种设计模式,主要用来解决复杂对象的构建问题,特别是在对象的构造过程中有大量可选参数时。在Java编程中,FreeBuilder是一个自动化工具,它可以帮助开发者为Java 1.6及更高版本的类自动生成Builder...
Builder模式是一种设计模式,主要用来解决复杂对象的构建问题,特别是在对象的构造过程中涉及大量的参数时。在Java编程中,Builder模式提供了一种更加灵活、结构化的创建对象的方式,避免了构造函数的过度膨胀和...
在Android开发中,Builder模式是一种常用的创建型设计模式,它能帮助我们构建复杂对象,同时保持构造过程的清晰和简洁。在本示例中,我们关注的是如何利用Builder模式来设置字体大小、颜色以及位置等属性。这在创建...