美文网首页
设计模式之建造者模式

设计模式之建造者模式

作者: 三不猴子 | 来源:发表于2018-12-06 23:15 被阅读5次

    建造者模式

    定义
    • 讲一个复杂的对象的狗桨与他的表示分离,使得同样的构建过程可以创建不同的表示。
    • 用户只需指定需要建造的类型就可以得到他们,建造过程及其细节不需要知道
    类型

    创建型

    适用场景
    • 如果一个对象有非常复杂的内部结构(很多属性)
    • 想把复杂对象的创建和使用分离
    优点
    • 封装性好,创建和使用分离
    • 拓展性好、建造类之间独立、一定程度上解耦
    缺点
    • 产生多余的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这个类。

    image

    从图中我们很明显可以看出这些方法都是返回这个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只是对构建进行封装而已,所以我们这个是建造者里面使用建造者。

    相关文章

      网友评论

          本文标题:设计模式之建造者模式

          本文链接:https://www.haomeiwen.com/subject/mzzacqtx.html