建造者模式 coding
生活随笔
收集整理的這篇文章主要介紹了
建造者模式 coding
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
建造者模式應用的非常廣泛,我們通過coding實戰一起來了解一下,建造者模式也是創建型,我們講的各種工廠也是創建型,當創建一個對象需要很多步驟時,適合使用建造者模式,而當需要一個簡單的方法,就可以簡單的創建一個對象時,適合使用工廠相關模式,這么說還不如直接coding的好,現在有一個業務場景,這個業務場景是說,建造一個網站的課程,但是建造者的應用場景有很多,例如說我們去蓋房子,建造一個房子,例如說我們要組裝主板,CPU,硬盤,內存等等,現在我們的業務場景就是說,建造一個視頻課程,例如我們的JAVA設計模式精講
和CourseBuilder進行一個組合,一個教練里面包含一個課程的,建造者他們是一比一的關系,然后持有的是一個抽象的建造者,下邊你是實際的建造者,并且實際的建造者中持有一個課程類,UML類圖還是非常簡單清晰明了的,這個就是一個標準的建造者,UML類圖,那實際的建造者就繼承了抽象類,實現里面的抽象方法,那現在我們創建一個測試類
主要關注Test,其他四個類關系沒有變,Test他和抽象的標準,和具體的課程呢,都沒有關系,但是他和教練有關系,他來創建這個指揮官,然后指揮官通過組合的方式,使用課程Builder這個抽象類,實際使用的是CourseActualBuilder,來創建這個Course,然后應用層通過這個教練拿到了具體的課程類,那我們現在想象一下,對于這個抽象類,有一個繼承他的實現類,而Test創建具體的Builder,也就是說我可以有很多的Builder,每個Builder他的特點他不一樣,例如我們還有一個前端課程的builder,里面還要builder一個前端資源,這個呢為了加以區分,我們還可以把它命名為后端課程的builder,所以根據實際課程的不同,我們在應用層可以選擇不同的Builder,來傳給課程經理,然后他拿到應用層,傳給他的具體Builder,來創建整個課程,也就是說把注入Builder的職責呢,現在是交給Test了,那當然還有一種方式,例如這個教學就是一個后端課程的教學,他完全不需要前端圖片的各種素材資源,那么我們可以把后端課程的builder,注入到后端課程經理當中,這樣應用層都不用關心builder,也就是說這個箭頭直接干掉,應用層只和具體的教學教練有關,也就是說應用層只和指揮官進行交互,這條線直接被砍掉,他們兩之間也不會建立關系,抽象類或接口builder都是OK的,只不過我們這里沒有一個具體的實現方法,所以使用抽象類還是接口,效果都是一樣的,那這里我們再演進一下,也就是這個指揮官教練,不是必須的,我們在演進的過程中,我們可以使用鏈式調用,我們在后續的coding當中,也會講一下在源碼框架中,一些鏈式調用的體現,我們在這里面創建一個V2版本
package com.learn.design.pattern.creational.builder;/*** 首先我們創建這個類Course* 還是這個課程類* 這個課程有幾個屬性* * * @author Leon.Sun**/
public class Course {/*** 課程的名字* 如果想在網站上上線一個課程的話* 名字是必須的* */private String courseName;/*** 還有課程所需要的PPT* */private String coursePPT;/*** 還有課程所需要的Video* 我們這里都先理解為String類型* */private String courseVideo;/*** 課程的手記* 四個元素有了之后呢* */private String courseArticle;//question & answer/*** 這里的QA表示問題和答案* */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;}@Overridepublic String toString() {return "Course{" +"courseName='" + courseName + '\'' +", coursePPT='" + coursePPT + '\'' +", courseVideo='" + courseVideo + '\'' +", courseArticle='" + courseArticle + '\'' +", courseQA='" + courseQA + '\'' +'}';}
}
package com.learn.design.pattern.creational.builder;/*** 課程的建造者* 如果抽象建造者都是抽象方法的話* 我們聲明成接口也是OK的* 只不過我們這里面先用抽象類* 那里面一共幾個屬性呢* 一共五個屬性* 然后開始寫他的build方法* 抽象方法寫完了* 抽象方法就是交給子類來實現的* 接下里我們要寫一個實現Builder的一個子類* * * @author Leon.Sun**/
public abstract class CourseBuilder {/*** 這里面傳入一個courseName* 這個是課程的建造者* 下面去build課程的各種元素* 同理其他的字段也是一樣的* * * @param courseName*/public abstract void buildCourseName(String courseName);public abstract void buildCoursePPT(String coursePPT);public abstract void buildCourseVideo(String courseVideo);/*** 課程的手記* * @param courseArticle*/public abstract void buildCourseArticle(String courseArticle);/*** 課程的問答* * @param courseQA*/public abstract void buildCourseQA(String courseQA);/*** 我們還要寫一個抽象方法* 返回一個Course* 叫做制作過程* 這么一個抽象的build就寫完了* * * @return*/public abstract Course makeCourse();
}
package com.learn.design.pattern.creational.builder;/*** 課程真正的build* 繼承CourseBuilder這個抽象類* 實現里面的方法* 這里面我們簡化一下* 合到實際的build當中* 下面的實現也非常的簡單* * * @author Leon.Sun**/
public class CourseActualBuilder extends CourseBuilder {private Course course = new Course();@Overridepublic void buildCourseName(String courseName) {/*** 直接把courseName傳進來* 下邊也都是同理* * 而這個Course是在Builder當中創建的* 也就是說private Course course = new Course();在這個位置* 所以調用了setCourseName* 現在里面的屬性都是空的* 然后courseName就賦值成功* 其他的屬性也是一樣的* * */course.setCourseName(courseName);}@Overridepublic void buildCoursePPT(String coursePPT) {course.setCoursePPT(coursePPT);}@Overridepublic void buildCourseVideo(String courseVideo) {course.setCourseVideo(courseVideo);}@Overridepublic void buildCourseArticle(String courseArticle) {course.setCourseArticle(courseArticle);}@Overridepublic void buildCourseQA(String courseQA) {course.setCourseQA(courseQA);}/*** 我們把斷點打到makeCourse這里面* 可以看到course其他的屬性都賦值成功了* 然后把這個course進行返回* * */@Overridepublic Course makeCourse() {/*** 上面的屬性都添加完之后呢* 我們這里面直接返回一個Course就OK了* 就完成了課程的一個制作* 這個時候我們要引入一個教練類* 教練起到什么作用呢* 很簡單* 講師和網站合作的時候* 網站會有工作人員和講師對接* 那這個人就可以稱之為課程教練* 或者教學經理* 他主要的職責就是和講師對接* 這里面我們來想一下* 公司的老板在下達課程任務的時候呢* 會直接和課程教練進行溝通* 然后課程教練和對應的講師進行對接* 然后來共同制作這個課程* 簡單的理解* 可以認為課程教練充當一個指揮官* 講師提交課程的名字* 提交課程的手記* 提交課程的視頻* 等等* 然后課程教練通過講師提供的各種資料* 來拼裝成這么一個課程* 后面我們也會演示一下構造者模式* 也就是說這個課程教練不是必須的* 不過我們的建造者也要演進兩個版本* 這樣也是為了更好地理解* 接下來我們就寫一下* * */return course;}}
package com.learn.design.pattern.creational.builder;/*** * @author Leon.Sun**/
public class Coach {/*** 這個教練肯定是含有我們的課程Builder* */private CourseBuilder courseBuilder;/*** 這個Builder我們通過set注入的方式注入進來* * * @param courseBuilder*/public void setCourseBuilder(CourseBuilder courseBuilder) {this.courseBuilder = courseBuilder;}/*** 在教練這個類里面肯定有一個行為* 返回值是課程* 里面要傳入課程的各種屬性* 首先是課程的名字* 還有課程的PPT* 課程的視頻* 課程的手記* 還有課程的問答* 一旦講師提交了這些給課程經理制造課程* 在制造這些課程的時候* 需要調用課程的Builder* * 在這里面打一個斷點* 首先傳入的值是下面看到的值* 然后里面調用的是courseBuilder* courseBuilder是private CourseBuilder courseBuilder這個對象* 之前new完之后通過set方法注入進來的* 然后他調用了buildCourseName* 進入到抽象類里面* 我們Ctrl + T進入到具體實現類* * * @param courseName* @param coursePPT* @param courseVideo* @param courseArticle* @param courseQA* @return*/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);/*** 就會返回Builder里面聲明的Course* * 這個時候就直接返回builder創建的course* 這么一個對象* 返回值類型是課程類型* * */return this.courseBuilder.makeCourse();}
}
package com.learn.design.pattern.creational.builder;/*** * @author Leon.Sun**/
public class Test {public static void main(String[] args) {/*** 抽象的父類引用創建一個子類的實現* * 首先創建一個Builder沒有什么好說的* */CourseBuilder courseBuilder = new CourseActualBuilder();/*** 然后new一個教練出來* * 然后創建一個教練* */Coach coach = new Coach();/*** 把這個Builder注入進去* 那現在就比較簡單* * 然后把這個builder放到教練里面* */coach.setCourseBuilder(courseBuilder);/*** 調用一下* 返回值是Course* 調用教學經理的makeCourse* 里面傳入參數* 首先是課程名稱"Java設計模式精講"* 然后第二個是PPT"Java設計模式精講PPT"* 第三個參數視頻* 第四個參數手記* 第五個參數問答* 也就是說現在創建這個課程* 是由指揮官教學教練來創建課程* 拿到講師提交的各種資料* 通過注入一個課程Builder* 這種方式呢* 來完成課程的健壯* * 然后看makeCourse關鍵方法* * */Course course = coach.makeCourse("Java設計模式精講","Java設計模式精講PPT","Java設計模式精講視頻","Java設計模式精講手記","Java設計模式精講問答");/*** 然后輸出這個課程* * 這個時候就開始輸出這個course* 整個課程就輸出出來了* 和預期保持一致* 我們在再看一下UML類圖* */System.out.println(course);}
}
這個類圖就比剛剛那個類圖簡單許多,作為課程實體類的建造者,而應用層只需要控制和哪個建造者進行交互,然后設置他具體的屬性,最后調用build這個方法,返回具體的實體類
package com.learn.design.pattern.creational.builder.v2;/*** v2版本中直接創建一個課程類* 這里就需要使用靜態的內部類* 而這個內部類不是一個建造者* 首先把這些屬性拿過來* 然后重寫一下toString方法* 為一會測試使用* 這種建造者模式使用的非常廣* 就是把具體的實體類和builder放在一個類當中* * * @author Leon.Sun**/
public class Course {/*** 這里面還是有這五個屬性* */private String courseName;private String coursePPT;private String courseVideo;private String courseArticle;//question & answerprivate String courseQA;/*** 這個Course需要一個構造器* 里面的參數改成courseBuilder* 而這個courseBuilder是靜態內部類* CourseBuilder這個類創建的對象* * * @param courseBuilder*/public Course(CourseBuilder courseBuilder) {/*** 所以我們再實現一下他的構造器* 這樣Course這個類的所有屬性就通過Builder來構建成功了* 我們現在再寫一個測試類* * 通過build里面獲取的屬性* 這個時候的this就是Course了* * */this.courseName = courseBuilder.courseName;this.coursePPT = courseBuilder.coursePPT;this.courseVideo = courseBuilder.courseVideo;this.courseArticle = courseBuilder.courseArticle;/*** 這里courseQA是空所以為空* this三個屬性都從courseBuilder獲取成功* 賦值到Course對象當中* * */this.courseQA = courseBuilder.courseQA;}@Overridepublic String toString() {return "Course{" +"courseName='" + courseName + '\'' +", coursePPT='" + coursePPT + '\'' +", courseVideo='" + courseVideo + '\'' +", courseArticle='" + courseArticle + '\'' +", courseQA='" + courseQA + '\'' +'}';}/*** 這么一個靜態內部類* * * @author Leon.Sun**/public static class CourseBuilder{private String courseName;private String coursePPT;private String courseVideo;private String courseArticle;//question & answerprivate String courseQA;/*** 直接寫一個方法buildCourseName* 傳一個String的buildCourseName* * 首先進入buildCourseName* * @param courseName* @return*/public CourseBuilder buildCourseName(String courseName){/*** 給build中的courseName賦值* 演進版在于鏈式調用* 注意這里返回的是本身CourseBuilder* * 首先這個build的this* 是Course下面的$的CourseBuilder* 里面的屬性都是空* 通過這種方式已經賦值了name了* 也就是把這個this本身返回回去* * */this.courseName = courseName;/*** return之后還可以調用其他的的方法* 因為這個build方法返回本身* 而它本身又持有各種方法* 一會寫測試的時候一起來體會鏈式調用* 非常簡單* 我們再copy一些方法過來* * */return this;}/*** 返回值統一成CourseBuilder* * 然后在PPT中再打個斷點* * * @param coursePPT* @return*/public CourseBuilder buildCoursePPT(String coursePPT) {/*** 首先這個this已經通過上面賦值成功了* 然后在這里面又把PPT賦值上* * */this.coursePPT = coursePPT;/*** 然后又把this返回回去* */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;}/*** 我們直接寫個方法* * 最后他又調用一下build方法* * @return*/public Course build(){/*** 傳入一個類* 把它自己傳入進來* * 這個時候this已經通過我們的應用層設置了是三個屬性* 都設置成功了* 還有兩個沒有設置所以為空* 當然我們的實際建造者可以寫一個默認值* 然后調用Course構造器* */return new Course(this);}}
}
package com.learn.design.pattern.creational.builder.v2;import com.google.common.collect.ImmutableSet;import java.util.Set;/*** 對于V2版本我們debug一下* 我們打個斷點* * * @author Leon.Sun**/
public class Test {public static void main(String[] args) {/*** 直接創建一個課程* 直接調用CourseBuilder對象* 很簡單* 現在這種方式是鏈式調用* 所以直接調用buildCourseName"Java設計模式精講"* 注意他的返回值是CourseBuilder* 我可以繼續來點* build什么呢* 比如他的PPT肯定是要的* buildCoursePPT* 所以把這個拿過來* 他的視頻也是要的* buildCourseVideo* 這些都是必須的* 他的手記不是必須的* 所以我可以不必build他的Article* 最后的返回值是Course* 還要調用一下他的build方法* 這個時候課程才創建成功* * */Course course = new Course.CourseBuilder().buildCourseName("Java設計模式精講").buildCoursePPT("Java設計模式精講PPT").buildCourseVideo("Java設計模式精講視頻").build();/*** 我們直接輸出run一下* 可以看到這里面都是輸出成功* courseArticle和courseQA是一個空值* 也就是這個可以按需調用* 這就是演進版本的最大優點* 這里又五個屬性* 如果屬性更多的話* 很容易寫串* 例如我們這里都是String類型* 例如我們賦值的位置不對* 或者把對象賦值錯了* 這個在實際的開發過程中* 也可能因為馬虎而發生* 而通過演進版的方式* 我們build什么屬性* 是非常明確的* 當然呢如果這里面就是寫錯了* 那也沒有辦法* 這個肯定是bug* 只不過通過這兩種方式的對象* 鏈式調用更方便點* 但是最后一定要調用build方法* 返回值才是具體的課程* 再看一下V2版本的類圖* * V2的方式在實際的應用中寫的也是比較多的* 首先它把具體的實體類和具體實體類的builder* 寫在一個類里* 包括以后維護什么的* 都會比較方便* 希望通過兩個版本的coding* 建造者模式有一個深刻的理解* 并且掌握牢固* 可以用到我們的實際項目當中* * * */System.out.println(course);Set<String> set = ImmutableSet.<String>builder().add("a").add("b").build();// System.out.println(set);}
}
?
總結
以上是生活随笔為你收集整理的建造者模式 coding的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 建造者模式讲解
- 下一篇: 建造者模式源码解析(jdk-guava+