建造者模式
定义
- 讲一个复杂的对象的狗桨与他的表示分离,使得同样的构建过程可以创建不同的表示。
- 用户只需指定需要建造的类型就可以得到他们,建造过程及其细节不需要知道
类型
创建型
适用场景
- 如果一个对象有非常复杂的内部结构(很多属性)
- 想把复杂对象的创建和使用分离
优点
- 封装性好,创建和使用分离
- 拓展性好、建造类之间独立、一定程度上解耦
缺点
- 产生多余的Builder对象
- 产品内部发生变化、建造者都要修改、成本较大。
建造者模式和工厂模式比较接近,其中建造者模式强调的方法的调用顺序。而工厂模式强调的是创建产品。另外他们的创建粒度也不同。建造者模式创建出来的产品复杂的,而工厂模式创建出出来的都是一个样。工厂模式注重的是把这个对象创建出来就可以。建造者模式不仅要创建产品还要知道这个产品的部件组成。
下面开始简单粗暴看代码 业务场景假设我们现在要制作课程,这个课程需要视频、ppt、文章的信息。同时我们在制作课程的时候还需要一个指导老师。
首先我们来创建一个课程类,把属性,set get toString 方法等填充一下。
public class Course {
    private String courseName;
    private String coursePPT;
    private String courseVideo;
    private String courseArticle;
    //question & answer
    private String courseQA;
    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 + '\'' +
                '}';
    }
}
紧接着我们创建一个抽象建造方法
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();
}
实体建造方法
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;
    }
}
我们前面说了这个课程我们还有个指导老师,下面我们来创建一个指导老师类。 通过这个指导老师我们对属性进行注入同时返回建造好了的对象。
public class Coach {
    private CourseBuilder courseBuilder;
    public void setCourseBuilder(CourseBuilder courseBuilder) {
        this.courseBuilder = courseBuilder;
    }
    public Course makeCourse(String courseName,String coursePPT,
                             String courseVideo,String courseArticle,
                             String courseQA){
        this.courseBuilder.buildCourseName(courseName);
        this.courseBuilder.buildCoursePPT(coursePPT);
        this.courseBuilder.buildCourseVideo(courseVideo);
        this.courseBuilder.buildCourseArticle(courseArticle);
        this.courseBuilder.buildCourseQA(courseQA);
        return this.courseBuilder.makeCourse();
    }
}
最后是测试类
public class BuilderTest {
    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);
    }
}
这个上面的代码是可以优化的,我们可以将课程类和课程的类的建造者放在同一个类中,将建造写成课程类的内部类。下面开始给出代码。 这里同时也使用了链式调用的方法。
public class Course {
    private String courseName;
    private String coursePPT;
    private String courseVideo;
    private String courseArticle;
    //question & answer
    private String courseQA;
    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;
        //question & answer
        private String courseQA;
        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);
        }
    }
}
此时应用的使用即为如下
public class V2BuilderTest {
    public static void main(String[] args) {
        Course course = new Course.CourseBuilder().buildCourseName("Java设计模式精讲")
                .buildCoursePPT("Java设计模式精讲PPT").buildCourseVideo("Java设计模式精讲视频").build();
        System.out.println(course);
    }
}
下面我们一起来看一下mybatis中对于建造者模式的应用吧,首先我们打开SqlSessionFactoryBuilder这个类。

从图中我们很明显可以看出这些方法都是返回这个SqlSessionFactory对象 还有这个XMLConfigBuilder(reader, environment, properties)明显就是解析mybatis xml配置的。 这里核心就是builder方法我们来看一下默认的builder方法。
public SqlSessionFactory build(Configuration config) {
    return new DefaultSqlSessionFactory(config);
  }
这里将配置传给默认的工厂进行构造。而Configuration是怎么来的呢,我们查看一下这个方法build(Reader reader, String environment, Properties 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.
      }
    }
  }
XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);这个方法是在建造这种再使用建造者。对xml文件解析,这里调用了parse方法,我们再查看一下这个parse方法看看。
  public Configuration parse() {
    if (parsed) {
      throw new BuilderException("Each XMLConfigBuilder can only be used once.");
    }
    parsed = true;
    parseConfiguration(parser.evalNode("/configuration"));
    return configuration;
  }
这里调用了parseConfiguration,我们再进去看一下这个里面parseConfiguration方法。
private void parseConfiguration(XNode root) {
    try {
      Properties settings = settingsAsPropertiess(root.evalNode("settings"));
      //issue #117 read properties first
      propertiesElement(root.evalNode("properties"));
      loadCustomVfs(settings);
      typeAliasesElement(root.evalNode("typeAliases"));
      pluginElement(root.evalNode("plugins"));
      objectFactoryElement(root.evalNode("objectFactory"));
      objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
      reflectorFactoryElement(root.evalNode("reflectorFactory"));
      settingsElement(settings);
      // read it after objectFactory and objectWrapperFactory issue #631
      environmentsElement(root.evalNode("environments"));
      databaseIdProviderElement(root.evalNode("databaseIdProvider"));
      typeHandlerElement(root.evalNode("typeHandlers"));
      mapperElement(root.evalNode("mappers"));
    } catch (Exception e) {
      throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
    }
  }
看到这里就非常清晰了,他主要负责个个组件的构建和装配。从上到下就是整个装配的流程。这才是复杂整个构建的核心,而SqlSessionFactory只是对构建进行封装而已,所以我们这个是建造者里面使用建造者。