建造者(Builder)
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
工厂方法模式注重的是整体对象的创建方法,而建造者模式注重的是部件构建的过程,旨在通过一步一步地精确构造创建出一个复杂的对象。
适用场景:
- 如果一个对象有非常复杂的内部结构(很多属性)
- 想把复杂对象的创建和使用分离
优缺点
优点:封装性好,创建和使用分离;扩展性好、建造类之间独立、一定程度上解耦。
缺点:产生多余的Builder对象;产品内部发生变化,建造者都要修改,成本较大。
应用场景
CourseBuilder
作为抽象建造者类,CourseActualBuilder
作为具体建造者类,Coach
作为教练类根据传入的建造者类安排复杂对象的建造次序(非必需),而Course
作为产品类。
抽象建造者CourseBuilder
:
public abstract class CourseBuilder {
public abstract void buildCourseName(String courseName);
public abstract void buildCoursePPT(String coursePPT);
public abstract void buildCourseVideo(String courseVideo);
public abstract void buildCourseArticle(String courseArticle);
public abstract void buildCourseQA(String courseQA);
public abstract Course makeCourse();
}
具体建造者CourseActualBuilder
:
public class CourseActualBuilder extends CourseBuilder {
private Course course = new Course();
@Override
public void buildCourseName(String courseName) {
course.setCourseName(courseName);
}
@Override
public void buildCoursePPT(String coursePPT) {
course.setCoursePPT(coursePPT);
}
@Override
public void buildCourseVideo(String courseVideo) {
course.setCourseVideo(courseVideo);
}
@Override
public void buildCourseArticle(String courseArticle) {
course.setCourseArticle(courseArticle);
}
@Override
public void buildCourseQA(String courseQA) {
course.setCourseQA(courseQA);
}
@Override
public Course makeCourse() {
return course;
}
}
教练Coach
:
public abstract class CourseBuilder {
public abstract void buildCourseName(String courseName);
public abstract void buildCoursePPT(String coursePPT);
public abstract void buildCourseVideo(String courseVideo);
public abstract void buildCourseArticle(String courseArticle);
public abstract void buildCourseQA(String courseQA);
public abstract Course makeCourse();
}
产品Course
:
public class Course {
private String courseName;
private String coursePPT;
private String courseVideo;
private String courseArticle;
private String courseQA; //question & answer
public String getCourseName() {
return courseName;
}
public void setCourseName(String courseName) {
this.courseName = courseName;
}
public String getCoursePPT() {
return coursePPT;
}
public void setCoursePPT(String coursePPT) {
this.coursePPT = coursePPT;
}
public String getCourseVideo() {
return courseVideo;
}
public void setCourseVideo(String courseVideo) {
this.courseVideo = courseVideo;
}
public String getCourseArticle() {
return courseArticle;
}
public void setCourseArticle(String courseArticle) {
this.courseArticle = courseArticle;
}
public String getCourseQA() {
return courseQA;
}
public void setCourseQA(String courseQA) {
this.courseQA = courseQA;
}
@Override
public String toString() {
return "Course{" +
"courseName='" + courseName + '\'' +
", coursePPT='" + coursePPT + '\'' +
", courseVideo='" + courseVideo + '\'' +
", courseArticle='" + courseArticle + '\'' +
", courseQA='" + courseQA + '\'' +
'}';
}
}
客户端Test
:
public class Test {
public static void main(String[] args) {
CourseBuilder courseBuilder = new CourseActualBuilder();
Coach coach = new Coach();
coach.setCourseBuilder(courseBuilder);
Course course = coach.makeCourse("Java设计模式", "Java设计模式PPT",
"Java设计模式视频", "Java设计模式笔记", "Java设计模式问答");
System.out.println(course);
}
}
客户端创建了一个建造者和一个教练,并将这个建造者作为参数传给教练,之后直接通过教练进行产品的创建,而对客户端隐藏了具体的创建细节。在教练内部,实际上是通过建造者一步步构造出复杂的产品的。
我们对以上的场景做进一步演化,省略了教练类,并且将建造者放在产品类的内部。这种做法在实际场景中更为常见,利于维护与扩展,并且支持链式调用。
产品类Course
以及作为建造者的内部类CourseBuilder
:
public class Course {
private String courseName;
private String coursePPT;
private String courseVideo;
private String courseArticle;
private String courseQA; //question & answer
public Course(CourseBuilder courseBuilder) {
this.courseName = courseBuilder.courseName;
this.coursePPT = courseBuilder.coursePPT;
this.courseVideo = courseBuilder.courseVideo;
this.courseArticle = courseBuilder.courseArticle;
this.courseQA = courseBuilder.courseQA;
}
@Override
public String toString() {
return "Course{" +
"courseName='" + courseName + '\'' +
", coursePPT='" + coursePPT + '\'' +
", courseVideo='" + courseVideo + '\'' +
", courseArticle='" + courseArticle + '\'' +
", courseQA='" + courseQA + '\'' +
'}';
}
public static class CourseBuilder{
private String courseName;
private String coursePPT;
private String courseVideo;
private String courseArticle;
private String courseQA; //question & answer
public CourseBuilder buildCourseName(String courseName){
this.courseName = courseName;
return this;
}
public CourseBuilder buildCoursePPT(String coursePPT) {
this.coursePPT = coursePPT;
return this;
}
public CourseBuilder buildCourseVideo(String courseVideo) {
this.courseVideo = courseVideo;
return this;
}
public CourseBuilder buildCourseArticle(String courseArticle) {
this.courseArticle = courseArticle;
return this;
}
public CourseBuilder buildCourseQA(String courseQA) {
this.courseQA = courseQA;
return this;
}
public Course build(){
return new Course(this);
}
}
}
CourseBuilder
中的每一个构建方法都返回对象自身,使得其支持链式调用,而build()
方法将建造者作为参数传给产品类的构造函数,其根据建造者初始化产品各属性值,并将构建完毕的产品返回。
客户端Test
:
public class Test {
public static void main(String[] args) {
Course course = new Course.CourseBuilder().buildCourseName("Java设计模式").buildCoursePPT("Java设计模式PPT").
buildCourseVideo("Java设计模式视频").build();
System.out.println(course);
}
}
可以看出,演进之后的建造过程更为简洁明了。
StringBuilder中的应用
Java.util.StringBuilder
类下的append
方法:
public final class StringBuilder
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
{
//...
public StringBuilder append(String str) {
super.append(str);
return this;
}
public StringBuilder append(StringBuffer sb) {
super.append(sb);
return this;
}
public StringBuilder append(CharSequence s) {
super.append(s);
return this;
}
public StringBuilder append(CharSequence s, int start, int end) {
super.append(s, start, end);
return this;
}
//...
可以看出,这里使用了建造者模式,append
方法总是返回建造者自身。StringBuilder
既担任建造者,又担任产品,而建造方法的实现由父类AbstractStringBuilder
完成。
StringBuffer
的实现与上面类似,区别在于StringBuffer
中的append
方法加了synchronized
关键字,因而是线程安全的。
mybatis中的应用
查看org.apache.ibatis.session
包下的SqlSessionFactoryBuilder
:
public class SqlSessionFactoryBuilder {
//...
public SqlSessionFactory build(Reader reader) {
return this.build((Reader)reader, (String)null, (Properties)null);
}
public SqlSessionFactory build(Reader reader, String environment) {
return this.build((Reader)reader, environment, (Properties)null);
}
public SqlSessionFactory build(Reader reader, Properties properties) {
return this.build((Reader)reader, (String)null, properties);
}
public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
SqlSessionFactory var5;
try {
XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
var5 = this.build(parser.parse());
} catch (Exception var14) {
throw ExceptionFactory.wrapException("Error building SqlSession.", var14);
} finally {
ErrorContext.instance().reset();
try {
reader.close();
} catch (IOException var13) {
;
}
}
return var5;
}
//...
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
这里面两个参数的build
方法大多直接调用后面三个参数的build
方法,返回值都为SqlSessionFactory
,而这个方法中又有另一个建造者XMLConfigBuilder
构建出一个Configuration
对象,我们查看XMLConfigBuilder
中的相关方法:
public Configuration parse() {
if (this.parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
} else {
this.parsed = true;
this.parseConfiguration(this.parser.evalNode("/configuration"));
return this.configuration;
}
}
private void parseConfiguration(XNode root) {
try {
Properties settings = this.settingsAsPropertiess(root.evalNode("settings"));
this.propertiesElement(root.evalNode("properties"));
this.loadCustomVfs(settings);
this.typeAliasesElement(root.evalNode("typeAliases"));
this.pluginElement(root.evalNode("plugins"));
this.objectFactoryElement(root.evalNode("objectFactory"));
this.objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
this.reflectorFactoryElement(root.evalNode("reflectorFactory"));
this.settingsElement(settings);
this.environmentsElement(root.evalNode("environments"));
this.databaseIdProviderElement(root.evalNode("databaseIdProvider"));
this.typeHandlerElement(root.evalNode("typeHandlers"));
this.mapperElement(root.evalNode("mappers"));
} catch (Exception var3) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + var3, var3);
}
}
构建出一个Configuration
对象的过程都在parseConfiguration
方法中,而parse
方法主要用来标记是否已经parse过并且返回构建好的Configuration
对象。