設計模式之建造者模式

建造者模式

定義
  • 講一個複雜的對象的狗槳與他的表示分離,使得一樣的構建過程能夠建立不一樣的表示。
  • 用戶只需指定須要建造的類型就能夠獲得他們,建造過程及其細節不須要知道
類型

建立型java

適用場景
  • 若是一個對象有很是複雜的內部結構(不少屬性)
  • 想把複雜對象的建立和使用分離
優勢
  • 封裝性好,建立和使用分離
  • 拓展性好、建造類之間獨立、必定程度上解耦
缺點
  • 產生多餘的Builder對象
  • 產品內部發生變化、建造者都要修改、成本較大。

建造者模式和工廠模式比較接近,其中建造者模式強調的方法的調用順序。而工廠模式強調的是建立產品。另外他們的建立粒度也不一樣。建造者模式建立出來的產品複雜的,而工廠模式建立出出來的都是一個樣。工廠模式注重的是把這個對象建立出來就能夠。建造者模式不只要建立產品還要知道這個產品的部件組成。設計模式

下面開始簡單粗暴看代碼 業務場景假設咱們如今要製做課程,這個課程須要視頻、ppt、文章的信息。同時咱們在製做課程的時候還須要一個指導老師。mybatis

首先咱們來建立一個課程類,把屬性,set get toString 方法等填充一下。app

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 + '\'' +
                '}';
    }
}
複製代碼

緊接着咱們建立一個抽象建造方法ide

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();
    }
}
複製代碼

最後是測試類ui

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);

    }
}
複製代碼

這個上面的代碼是能夠優化的,咱們能夠將課程類和課程的類的建造者放在同一個類中,將建造寫成課程類的內部類。下面開始給出代碼。 這裏同時也使用了鏈式調用的方法。this

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);
        }

    }
}
複製代碼

此時應用的使用即爲以下spa

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只是對構建進行封裝而已,因此咱們這個是建造者裏面使用建造者。

相關文章
相關標籤/搜索