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

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 set = ImmutableSet.builder().add("a").add("b").build();// System.out.println(set);}
}
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!