1 定义域特征

定义:将一个复杂的对象构建与其表示分离,使得同样的构建过程可以创建不同的表示。特征:用户只需要指定需要建造的类型即可,对于中间的细节不考虑。

本质:分离整体构建算法和部件构造。构建一个复杂的对象,本来就有构建的过程,以及构建过程中具体的实现。生成器模式就是用来分离这两个部分,从而使得程序结构更松散、扩展更容易、复用性更好,同时也会使得代码更清晰,意图更明确。

虽然在生成器模式的整体构建算法中,会一步一步引导 Builder来构建对象,但这不是说生成器主要就是用来实现分步骤构建对象的。生成器模式的重心还是在于分离整体构建算法和部件构造,而分步构建对象不过是整体构建算法的一个简单表现,或者说是一个附带产物。

优点:

(1)松散耦合

生成器模式可以用同一个构建算法构建出表现上完全不同的产品,实现产品构建和产品表现上的分离。生成器模式正是把产品构建的过程独立出来,使它和具体产品的表现松散耦合,从而使得构建算法可以复用,而具体产品表现也可以灵活地、方便地扩展和切换。

(2)可以很容易地改变产品的内部表示

在生成器模式中,由于 Builder i对象只是提供接口给 Director使用,那么具体的部件创建和装配方式是被 Builder接口隐藏了的, Director并不知道这些具体的实现细节。这样一来,要想改变产品的内部表示,只需要切换 Builder的具体实现即可,不用管 Director,因此变得很容易

(3)更好的复用性

生成器模式很好地实现了构建算法和具体产品实现的分离。这样一来,使得构建产品的算法可以复用。同样的道理,具体产品的实现也可以复用,同一个产品的实现,可以配合不同的构建算法使用

使用场景:如果创建对象的算法,应该独立于该对象的组成部分以及它们的装配方式时。如果同一个构建过程有着不同的表示时。

2 代码实现及分析

场景:假设需要创建一个文档,该文档可以是txt、html形式的单独或者组合一起实用的,后续可能还会添加excel和word格式的。

Builder类:抽象类定义了创建一个文档所用到的所有方法

public abstract  class Builder {
//创建一个文档标题,可能还会有很多方法这里就先写一个
public abstract void makeTitle(String title);
}

HtmlBuilder类:创建一个Html文档

public class HtmlBuilder extends Builder{

    public void makeTitle(String title){
System.out.println("HtmlBuilder: " + title);
}
//HtmlBuilder内部所有特有的方法
public void make(){
System.out.println("HtmlBuilder特有方法");
}
}

TxtBuilder类:创建一个txt文档

public class TxtBuilder extends Builder {
public void makeTitle(String title){
System.out.println("TxtBuilder:" + title);
}
//TxtBuilder内部所有特有的方法
public void make(){
System.out.println("TextBuilder特有方法");
}
}

Director类:负责实例传递并进行调用

public class Directer {
private Builder builder;
//set方式注入对象
public void setBuilder(Builder builder){
this.builder = builder;
} public void makeTitle(String title){
builder.makeTitle(title);
}
}

对于Director类是并不知道具体是由谁来进行实现的,因为是在应用层进行的控制。正是因为只有不知道子类才能进行替换,所以在Director类中实现了可替换性。因为可替换所以在应用层才能进行随意的切换调用,此外基于这个原因在Director类中是不能调用文档类的特有方法,在这里可以认为文档类的特有方法是文档内部编写所需要的,而在Director类中是并不关心内部是如何完成的。

Test类:应用层 指定创建什么样式的文档。

public class Test {
public static void main(String[] args) { Directer directer = new Directer();
//让TxtBuilder创建文档
TxtBuilder textBuilder = new TxtBuilder();
directer.setBuilder(textBuilder);
directer.makeTitle("创建文档"); //让HtmlBuilder创建文档
HtmlBuilder htmlBuilder = new HtmlBuilder();
directer.setBuilder(htmlBuilder);
directer.makeTitle("创建文档"); }
}

UML图:

下面这个场景是最初写的样例,感觉没有第一个场景样例更为贴切。

场景:假设一个课程有许多部分组成:PPT、视频、手记、问答,需要在应用层根据不同要求创建不同的课程并设置相应的组成部分。

course类:

//课程类
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 + '\'' +
'}';
}
}

CourserBuilder:抽象的课程建造者

/**
* 课程建造者
*/
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(); }

CourserActualBuilder:

/**
* 课程的真实构建类
*/
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;
}
}

Coach:辅助类

/**
* 课程教练,通过接收到的课程信息来构建课程。
*/
public class Coach { private CourseBuilder courseBuilder; //set方式注入
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();
}
}

Test类:应用层

/**
* 测试类
*/
public class Test {
public static void main(String[] args) {
//多态父类引用子类实现
CourseBuilder courseBuilder = new CourseActualBuilder();
Coach coach = new Coach();
//在coach中注入courseBuilder
coach.setCourseBuilder(courseBuilder); Course course = coach.makeCourse("Java设计模式精讲", "Java设计模式精讲PPT", "Java设计模式精讲视频",
"Java设计模式精讲手记","Java设计模式精讲问答");

System.out.println(course); }
}

在应用层中通过向coach传递参数来构建一个具体的对象,coach和CourserBuilder为组合的关系,1对1。CourserActualBuilder与Course同样为组合的1对1关系,其类图关系如下图所示。

3 优化

对于上面的代码,coach不是必须的可以让应用层直接控制,采用静态内部类进行改善。

Course类:

public class Course {

    private String courseName;
private String coursePPT;
private String courseVideo;
private String courseArticle;
//question & answer
private String courseQA; //这里的CourseBuilder就是静态内部类返回的对象
public Course(CourseBuilder courseBuilder) {
this.courseName = courseBuilder.courseName;
this.coursePPT = courseBuilder.coursePPT;
this.courseVideo = courseBuilder.courseVideo;
this.courseArticle = courseBuilder.courseArticle;
this.courseQA = courseBuilder.courseQA;
} //采用静态内部类创建Course对象
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);
}
} @Override
public String toString() {
return "Course{" +
"courseName='" + courseName + '\'' +
", coursePPT='" + coursePPT + '\'' +
", courseVideo='" + courseVideo + '\'' +
", courseArticle='" + courseArticle + '\'' +
", courseQA='" + courseQA + '\'' +
'}';
}
}

Test类:

public class Test {
public static void main(String[] args) {
//链式调用
Course course = new Course.CourseBuilder().buildCourseName("Java设计模式精讲").buildCoursePPT("Java设计模式精讲PPT").buildCourseVideo("Java设计模式精讲视频").build();
System.out.println(course);
}
}

这样其类比上部分要简化很多,其关系图如下:

4  源码分析

(1)JDK源码

StringBuilder类中的append方法:

public StringBuilder append(StringBuffer sb) {
super.append(sb);
return this;
} @Override
public StringBuilder append(CharSequence s) {
super.append(s);
return this;
}

可以看出与优化部分的代码类似StringBuilder在建造时没有采用过多的抽象而是采用链式方法直接进行修改。同样的还有StringBuffer,加了关键字synchronized保证了其线程安全

@Override
public synchronized StringBuffer append(Object obj) {
toStringCache = null;
super.append(String.valueOf(obj));
return this;
} @Override
public synchronized StringBuffer append(String str) {
toStringCache = null;
super.append(str);
return this;
}

(2)mybatis源码

在SqlSessionFactoryBuilder类中的build方法:根据传入的confi构建默认的SqlSession

public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}

寻找Configuration具体怎么来的,首先在SqlSessionFactoryBuilder类中有如下代码:

//在XMLConfigBuilder完成复杂创建的基础上,做一层简单的封装,这里用建造者来包装一层建造者
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
SqlSessionFactory var5;
try {
//在建造者模式中使用建造者,XMLConfigBuilder负责完成复杂流程的创建
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
var5 = this.build(parser.parse());
} catch (Exception var14) {
throw ExceptionFactory.wrapException("Error building SqlSession.", var14);
} finally {
ErrorContext.instance().reset(); try {
inputStream.close();
} catch (IOException var13) {
;
} } return var5;
}

在上述代码中深入:var5 = this.build(parser.parse());深入parse()方法在XMLConfigBuilder类中有:此时得到了Configuration

public Configuration parse() {
if (this.parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
} else {
this.parsed = true;
//调用方法
this.parseConfiguration(this.parser.evalNode("/configuration"));
return this.configuration;
}
}

继续深入:this.parseConfiguration方法便可达到复杂配置对象配置流程,至此建造者模式套用建造者模式的流程全部结束。

//XNode根节点,完成复杂流程的封装工作
private void parseConfiguration(XNode root) {
try {
Properties settings = this.settingsAsPropertiess(root.evalNode("settings"));
this.propertiesElement(root.evalNode("properties"));
this.loadCustomVfs(settings);
this.typeAliasesElement(root.evalNode("typeAliases"));
this.pluginElement(root.evalNode("plugins"));
this.objectFactoryElement(root.evalNode("objectFactory"));
this.objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
this.reflectorFactoryElement(root.evalNode("reflectorFactory"));
this.settingsElement(settings);
this.environmentsElement(root.evalNode("environments"));
this.databaseIdProviderElement(root.evalNode("databaseIdProvider"));
this.typeHandlerElement(root.evalNode("typeHandlers"));
this.mapperElement(root.evalNode("mappers"));
} catch (Exception var3) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + var3, var3);
}
}

5 相关设计模式

(1)生成器模式和工厂方法模式

这两个模式可以组合使用。生成器模式的 Builder实现中,通常需要选择具体的部件实现。一个可行的方案就是实现成为工厂方法,通过工厂方法来获取具体的部件对象,然后再进行部件的装配。

(2)生成器模式和抽象工厂模式

区别:抽象工厂模式的主要目的是创建产品簇,这个产品簇里面的单个产品就相当于是构成一个复杂对象的部件对象,抽象工厂对象创建完成后就立即返回整个产品簇;而生成器模式的主要目的是按照构造算法,一步一步来构建一个复杂的产品对象,通常要等到整个构建过程结束以后,才会得到最终的产品对象。

事实上,这两个模式是可以组合使用的。在生成器模式的 Builder实现中,需要创建各个部件对象,而这些部件对象是有关联的,通常是构成一个复杂对象的部件对象。也就是说, Builder实现中,需要获取构成一个复杂对象的产品簇,那自然就可以使用抽象工厂模式来实现。这样一来,由抽象工厂模式负贵了部件对象的创建, Builder实现里面则主要负责产品对象整体的构建了。

(3)生成器模式和模板方法模式

模板方法模式主要是用来定义算法的骨架,把算法中某些步骤延退到子类中实现。再想想生成器模式,Director(coach)用来定义整体的构建算法,把算法中某些涉及到具体部件对象的创建和装配的功能,委托给具体的 Builder来实现。虽然生成器不是延迟到子类,是委托给 Builder,但那只是具体实现方式上的差别,从实质上看两个模式很类似,都是定义一个固定的算法骨架,然后把算法中的某些具体步骤交给其他类来完成,都能实现整体算法步骤和某些具体步骤实现的分离。

当然这两个模式也有很大的区别,首先是模式的目的,生成器模式是用来构建复杂对象的,而模板方法是用来定义算法骨架,尤其是一些复杂的业务功能的处理算法的骨架;其次是模式的实现,生成器模式是采用委托的方法,而模板方法采用的是继承的方式;另外从使用的复杂度上,生成器模式需要组合Director(coach)和 Builder对象,然后才能开始构建,要等构建完后才能获得最终的对象,而模板方法就没有这么麻烦,直接使用子类对象即可。

(4)生成器模式和组合模式

这两个模式可以组合使用。对于复杂的组合结构,可以使用生成器模式来一步一步构建

0

建造者模式(Builder)---创建型的更多相关文章

  1. Java设计模式——建造者模式(创建型模式)

    概述   建造者模式也称为生成器模式,是一种对象创建型模式,它可以将复杂对象的建造过程抽象出来(抽象类别),使这个抽象过程的不同实现方法可以构造出不同表现(属性)的对象.   建造者模式意在为重叠构造 ...

  2. Java设计模式04:常用设计模式之建造者模式(创建型模式)

    1. Java之建造者模式(Builder Pattern) (1)概念:       将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示. [ 构建与表示分离, 同构建不同表示 ] ...

  3. 大白话建造者模式(Builder Pattern)

    前言 起初打算按照之前的日产系列写建造者模式.但参考了网上的很多文章,让我对建造者模式更加的困惑,也害怕自己无法已易懂的方式进行解释.最后通过Google发现了一篇英文文章Builder,使我茅塞顿开 ...

  4. 设计模式学习之建造者模式(Builder,创建型模式)(6)

    假如我们需要建造一个房子,并且我们也不知道如何去建造房子,所以就去找别人帮我们造房子 第一步: 新建一个房子类House,里面有房子该有的属性,我们去找房子建造者接口HouseBuilder,我们要建 ...

  5. 设计模式系列之建造者模式(Builder Pattern)——复杂对象的组装与创建

    说明:设计模式系列文章是读刘伟所著<设计模式的艺术之道(软件开发人员内功修炼之道)>一书的阅读笔记.个人感觉这本书讲的不错,有兴趣推荐读一读.详细内容也可以看看此书作者的博客https:/ ...

  6. 设计模式03: Builder 生成器模式(创建型模式)

    Builder生成器模式(创建型模式) Builder模式缘起假设创建游戏中的一个房屋House设施,该房屋的构建由几个部分组成,且各个部分富于变化.如果使用最直观的设计方法,每个房屋部分的变化,都将 ...

  7. 【设计模式】建造者模式 Builder Pattern

    前面学习了简单工厂模式,工厂方法模式以及抽象工厂模式,这些都是创建类的对象所使用的一些常用的方法和套路, 那么如果我们创建一个很复杂的对象可上面的三种方法都不太适合,那么“专业的事交给专业人去做”,2 ...

  8. C3:建造者模式 Builder

    将一个复杂对象的创建与表示分离,使得同样的构建过程可以创建不同的表示. 应用场景: A.创建这个对象通常需要较多的参数,才能完整的表示该对象.B.类的各个组成部分的具体实现类或算法经常面临变化,但将他 ...

  9. 设计模式—建造者模式(Builder)

    title: 设计模式-建造者模式 建造者模式(Builder)是一步一步创建一个复杂的对象,它允许用户只通过指定复杂对象的类型和内容就可以构建它们,用户不需要知道内部的具体构建细节.建造者模式属于对 ...

  10. 【原】iOS设计模式之:建造者模式Builder Pattern,用于改进初始化参数

    本文主要讨论一下iOS中的Builder Pattern.与网上很多版本不同,本文不去长篇大论地解释建造者模式的概念,那些东西太虚了.设计模式这种东西是为了解决实际问题的,不能为了设计模式而设计模式, ...

随机推荐

  1. 【青橙商城-管理后台开发】3. web模块搭建

    [青橙商城-管理后台开发]3. web模块搭建 1.创建qingcheng_web_manager模块 pom.xml <?xml version="1.0" encodin ...

  2. JWT与Session比较和作用

    1. JSON Web Token是什么 JSON Web Token (JWT)是一个开放标准(RFC 7519),它定义了一种紧凑的.自包含的方式,用于作为JSON对象在各方之间安全地传输信息.该 ...

  3. Struts2的学习自我总结

    Struts2是一个轻量的的开源的框架,可以实现mvc的模式,起初struts和webwork两家公司都存在,后来strus的技术要落后一些,但是使用人群比较广泛,为了避免今后struts被淘汰,st ...

  4. DFA与动态规划

    1.牛客练习赛45 A 给定字符串, 求字符不相邻的"QAQ"子序列个数. $dp[i][0]$ 只匹配一个'Q'的方案数的前缀和. $dp[i][1]$ 只匹配"QA& ...

  5. element-ui组件dialog遇到form

    Vue.js似乎成了一种潮流. UI框架element-ui也跟着成了一种潮流,不过得承认,至少我个人还是非常认可的,element-ui做的是真不错. 用到element-ui,那么在dialog中 ...

  6. Python实现乘法表——在列表里进行for循环设初值

    代码:最大的收获是二维列表的实现:[0]*9结果是[0,0,0,0,0,0,0,0,0,0],再加上for i in range(9),代表是9行[0,0,0,0,0,0,0,0,0,0],也就是9* ...

  7. GC原理图

    GC原理图,Jdk1.6及以下版本 永久代 永久代是Hotspot虚拟机特有的概念,是方法区的一种实现,别的JVM都没有这个东西.在Java 8中,永久代被彻底移除,取而代之的是另一块与堆不相连的本地 ...

  8. LLVM新建全局变量

    在LLVM中,有原生的AST Clone,却没有一个比较好的Stmt copy功能,基于Scout在LLVM上进行的修改,我们实现了自己的Stmt Clone功能. 要进行Stmt Clone,肯定需 ...

  9. 1.JavaWeb 知识点概览

    1.tomcat服务器的安装和配置.http协议 1.1 虚拟目录的 /*映射*/(配置Context元素)(server.xml catalina\localhost\) http://blog.c ...

  10. OverflowError:django signed integer is greater than maximum 数据库日期字段相关错

    使用django中的默认数据库sqlite3, 在pycharm中录入日期字段相关信息结果出现问题 在保存的时候如图 直接在界面选择的日期变成了时间戳, 并且在获取数据的时候报错 经过查询之后(舔大佬 ...