天天看點

設計模式-建造者模式(Builder Pattern)

推薦:​​Java設計模式彙總​​

建造者模式

定義

将一個複雜對象的建構與它的表示分離,使得同樣的建構過程可以建立不同的表示。

建立者模式隐藏了複雜對象的建立過程,它把複雜對象的建立過程加以抽象,通過子類繼承或者重載的方式,動态的建立具有複合屬性的對象。

類型

建立型。

例子

Course類(課程類),一個産品類。

package com.kaven.design.pattern.creational.builder;

public class Course {

    private String courseName;
    private String coursePPT;
    private String courseVideo;
    private String courseArticle;

    //question and answer
    private String courseQA;

    public void setCourseName(String courseName) {
        this.courseName = courseName;
    }

    public void setCoursePPT(String coursePPT) {
        this.coursePPT = coursePPT;
    }

    public void setCourseVideo(String courseVideo) {
        this.courseVideo = courseVideo;
    }

    public void setCourseArticle(String courseArticle) {
        this.courseArticle = courseArticle;
    }

    public void setCourseQA(String courseQA) {
        this.courseQA = courseQA;
    }

    @Override
    public String toString() {
        return "Course{" +
                "courseName='" + courseName + '\'' +
                ", coursePPT='" + coursePPT + '\'' +
                ", courseVideo='" + courseVideo + '\'' +
                ", courseArticle='" + courseArticle + '\'' +
                ", courseQA='" + courseQA + '\'' +
                '}';
    }
}      

CourseBuilder類(抽象類,也可以定義為接口),是課程(産品)的抽象建造者類,定義建立課程執行個體的各種接口。

package com.kaven.design.pattern.creational.builder;

public abstract class CourseBuilder {

    public abstract void builderCourseName(String courseName);
    public abstract void builderCoursePPT(String coursePPT);
    public abstract void builderCourseVideo(String courseVideo);
    public abstract void builderCourseArticle(String courseArticle);
    public abstract void builderCourseQA(String courseQA);

    public abstract Course makeCourse();
}      

CourseActualBuilder類,是課程(産品)真正的建立者類。

package com.kaven.design.pattern.creational.builder;

public class CourseActualBuilder extends CourseBuilder {

    private Course course = new Course();

    public void builderCourseName(String courseName) {
        course.setCourseName(courseName);
    }

    public void builderCoursePPT(String coursePPT) {
        course.setCoursePPT(coursePPT);
    }

    public void builderCourseVideo(String courseVideo) {
        course.setCourseVideo(courseVideo);
    }

    public void builderCourseArticle(String courseArticle) {
        course.setCourseArticle(courseArticle);
    }

    public void builderCourseQA(String courseQA) {
        course.setCourseQA(courseQA);
    }

    public Course makeCourse() {
        return course;
    }
}      

Coach類,是一個指揮者類,應用層可以通過指揮者類進行産品執行個體的建立,而不是直接調用建造者類的相關方法。

package com.kaven.design.pattern.creational.builder;

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.builderCourseName(courseName);
        this.courseBuilder.builderCoursePPT(coursePPT);
        this.courseBuilder.builderCourseVideo(courseVideo);
        this.courseBuilder.builderCourseArticle(courseArticle);
        this.courseBuilder.builderCourseQA(courseQA);
        return this.courseBuilder.makeCourse();

    }
}      

應用層代碼:

package com.kaven.design.pattern.creational.builder;

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{courseName='Java設計模式', coursePPT='Java設計模式PPT', courseVideo='Java設計模式視訊', courseArticle='Java設計模式手記', courseQA='Java設計模式問答'}      

這便是一個建造者模式的例子,不過看起來還是挺複雜的。

改進

使用靜态内部類可以改進建造者模式。

Course類(課程類),與上面的Course類一樣,是一個産品類。

但在Course類中定義了一個靜态内部類CourseBuilder,并且這個靜态内部類CourseBuilder就是課程執行個體的實際建造者,可以好好體會下面的代碼。

package com.kaven.design.pattern.creational.builder.v2;

public class Course {

    private String courseName;
    private String coursePPT;
    private String courseVideo;
    private String courseArticle;

    //question and 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 and 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);
        }
    }
}      

應用層代碼:

由于上面的改進,建立課程執行個體的建造者模式更加簡潔,并且在應用層建立課程執行個體時更加友好(通過鍊式調用對課程執行個體屬性進行初始化,​

​關鍵在于靜态内部類CourseBuilder中的buildxxx()方法都是傳回this​

​​)。

根據靜态内部類CourseBuilder中的代碼可以看出,每次調用buildxxx()方法其實都是初始化靜态内部類CourseBuilder執行個體的xxx屬性,最後通過調用build()方法,将this傳給Course類的構造方法建立課程執行個體(此時this的屬性都已經有值了,再通過this的這些屬性值來初始化課程執行個體的屬性)。

package com.kaven.design.pattern.creational.builder.v2;

public class Test {
    public static void main(String[] args) {
        Course course = new Course.CourseBuilder().buildCourseName("Java設計模式")
                .buildCoursePPT("Java設計模式PPT").buildCourseVideo("Java設計模式視訊")
                .buildCourseArticle("Java設計模式手記").buildCourseQA("Java設計模式問答").build();
        System.out.println(course );
    }
}      

與未改進的版本相比,通過鍊式調用對課程執行個體屬性進行初始化更加友好,還不容易出錯,像下面建立課程執行個體的代碼,屬性值很容易寫錯位置,改進版本的建造者模式在很多中間件以及架構中有使用。

Course course = coach.makeCourse("Java設計模式","Java設計模式PPT",
                "Java設計模式視訊","Java設計模式手記","Java設計模式問答");      

結果是一樣的。

Course{courseName='Java設計模式', coursePPT='Java設計模式PPT', courseVideo='Java設計模式視訊', courseArticle='Java設計模式手記', courseQA='Java設計模式問答'}      

适用場景

  1. 需要生成的産品對象有複雜的内部結構,這些産品對象具備共性。
  2. 隔離複雜對象的建立和使用,并使得相同的建構過程可以建立不同的産品。

建造者模式與抽象工廠模式的比較

  • 與抽象工廠模式相比,建造者模式傳回一個組裝好的完整産品,而抽象工廠模式傳回一系列相關的産品,這些産品位于不同的産品等級結構,構成了一個産品族。
  • 在抽象工廠模式中,應用層執行個體化工廠類,然後調用工廠方法擷取所需産品對象,​

    ​而在建造者模式中,應用層可以不直接調用建造者類的相關方法,而是通過指揮者類來指導如何生成對象​

    ​,包括對象的組裝過程和建造步驟,它側重于一步步構造一個複雜對象,傳回一個完整的對象。
  • 如果将抽象工廠模式看成汽車配件生産工廠,生産一個産品族的産品,那麼建造者模式就是一個汽車組裝工廠,通過對部件的組裝可以傳回一輛完整的汽車

​​設計模式-抽象工廠模式(Abstract Factory Pattern)​​

優點

  1. 使用建造者模式可以使應用層不必知道産品内部組成的細節。
  2. 具體的建造者類之間是互相獨立的,這有利于系統的擴充。
  3. 具體的建造者互相獨立,是以可以對建造的過程逐漸細化,而不會對其他子產品産生任何影響。
  1. 建造者模式所建立的産品一般具有較多的共同點,其組成部分相似;如果産品之間的差異性很大,則不适合使用建造者模式,是以其使用範圍受到一定的限制。
  2. 如果産品的内部變化複雜,可能會導緻需要定義很多具體建造者類來實作這種變化,導緻系統變得很龐大。