前言

“我要打十个”,其实是我要打十个野怪!

这十个野怪呢,它们有不同的技能、装备和武器,长得也不一样。这里野怪是一个蛮复杂的对象,由各个不同的部分组成(技能、装备、武器等),不同的野怪的它们各部分之间的构成方式就不同。因此,要创建这种复杂对象,就需要使用建造者模式。

什么是建造者模式

首先建造者模式Gof 23种设计模式之一。也叫Builder模式。

是将一个复杂对象的构建和其表示相分离,使得同样的构建过程可以创建不同的表示。

我们来品一品这句话,首先是复杂对象,这个复杂对象中可能包含了多个不同的其他对象。其次是这个复杂对象的创建一定是用到了这些其他对象,通过一定的算法组合能才创建出这个对象。最后就是它能通过builder创建出一些特性不同但相似的对象。

好了,借用Linus 名言:

Talk is cheap. Show me the code!!!

代码实现

开始创建我们的野怪类,就叫做Hero吧,它的组成部分有技能类Skill,装备类Armor 和武器类Weapon 。

创建Skill、Armor和Weapon类

public class Skill {
private String skillName; public Skill(String skillName) {
this.skillName = skillName;
} @Override
public String toString() {
return "Skill{" +
"skillName='" + skillName + '\'' +
'}';
}
} public class Armor {
private String armorName; public Armor(String armorName) {
this.armorName = armorName;
} @Override
public String toString() {
return "Armor{" +
"armorName='" + armorName + '\'' +
'}';
}
} public class Weapon {
private String weaponName; public Weapon(String weaponName) {
this.weaponName = weaponName;
} @Override
public String toString() {
return "Weapon{" +
"weaponName='" + weaponName + '\'' +
'}';
}
}

创建Hero类,在该类中,我们使用静态内部类的方式构建了Builder类,就是我们使用Builder类帮助我们创建对象。

忘了啥是内部类的,可以移驾下面这篇复习下。

Java内部类超详细总结(含代码示例)

public class Hero {
private final String name;
private final Skill skill;
private final Armor armor;
private final Weapon weapon; private Hero(Builder builder){
this.name = builder.name;
this.skill = builder.skill;
this.armor = builder.armor;
this.weapon = builder.weapon;
} @Override
public String toString() {
return "Hero{" +
"name='" + name + '\'' +
", skill=" + skill +
", armor=" + armor +
", weapon=" + weapon +
'}';
} public static class Builder{
private final String name;
private Skill skill;
private Armor armor;
private Weapon weapon; public Builder(String name){
this.name = name;
} public Builder withSkill(Skill skill){
this.skill = skill;
return this;
} public Builder withArmor(Armor armor){
this.armor = armor;
return this;
} public Builder withWeapon(Weapon weapon){
this.weapon = weapon;
return this;
} public Hero build(){
return new Hero(this);
}
}
}

好了,我们的builder模式的核心代码已经晚了,其实关键的就是Builder类,我们创建复杂对象就是通过Builder类封装了创建的细节,同时,Builder提供了一些公共方法,可以定制这些复杂对象的创建过程。

新建个测试类AppMain,测试一把。

public class AppMain {
public static void main(String[] args) {
Hero hero = new Hero.Builder("纳什男爵")
.withSkill(new Skill("飞龙在天"))
.withArmor(new Armor("亢龙铠甲"))
.withWeapon(new Weapon("唾沫星子"))
.build(); System.out.println(hero);
}
}

结果如下:

Hero{name='纳什男爵', skill=Skill{skillName='飞龙在天'}, armor=Armor{armorName='亢龙铠甲'}, weapon=Weapon{weaponName='唾沫星子'}}

当然了,这里也可以创建个“四鸟”,“河蟹”之类的。总之,你要打十个,么有问题啊,我们给你builder十个就好了,而且是不重样的。

Builder模式在源码中的应用

StringBuilder

其实我们熟知的StringBuilder就是builder模式的典型实现。我们平时使用基本都是这样:

        StringBuilder sb = new StringBuilder();
sb.append(123).append('a')
.append(1.23)
.append(true)
.append("hhhh");

看着就很平常,soeasy的感觉,其实可以看到它能添加不同的数据类型进去,对应建造者模式中的各个部分,通过append方法的不同组合构建出了不同的StringBuilder对象。

看下源码:

    ......

    @Override
public StringBuilder append(boolean b) {
super.append(b);
return this;
} @Override
public StringBuilder append(char c) {
super.append(c);
return this;
}
......

上面列举了两个重载方法,可以看到其实是调用了父类的重载方法,父类是AbstractStringBuilder

	// 这里只列举这一个父类的方法
public AbstractStringBuilder append(boolean b) {
if (b) {
ensureCapacityInternal(count + 4);
value[count++] = 't';
value[count++] = 'r';
value[count++] = 'u';
value[count++] = 'e';
} else {
ensureCapacityInternal(count + 5);
value[count++] = 'f';
value[count++] = 'a';
value[count++] = 'l';
value[count++] = 's';
value[count++] = 'e';
}
return this;
}

Mybatis中的builder模式

Mybatis中的SqlSessionFactoryBuilder、XMLMapperBuilder、XMLStatementBuilder等都使用了builder模式。

这里简单看下SqlSessionFactoryBuilder

所有的build重载方法都在构建SqlSessionFactory 对象。只是可以根据需要调用不同的方法,传入不同的参数,就可以构建出特性不同的SqlSessionFactory 。

看下其中一个build方法的源码

    ......

    public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
SqlSessionFactory var5;
try {
XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
var5 = this.build(parser.parse());
} catch (Exception var14) {
throw ExceptionFactory.wrapException("Error building SqlSession.", var14);
} finally {
ErrorContext.instance().reset(); try {
reader.close();
} catch (IOException var13) {
} } return var5;
}
......

而且可以看到,这个方法中又使用了一个XMLConfigBuilder 。

Builder模式的使用场景

下面再总结一下builder模式的使用场景吧。

  • 创建复杂对象的算法应该独立于组成对象的部件及其组装方式。
  • 构造对象的过程允许所构造的对象的不同表示。

设计模式往期回顾

Java面试必备:手写单例模式

工厂模式超详解(代码示例)

设计模式之原型模式

设计模式之代理模式

设计模式之委派模式,大名鼎鼎的Spring都在用

公众号:二营长的笔记

免费领资料:公众号内回复“二营长”

我要打十个!详解建造者模式(builder pattern)的更多相关文章

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

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

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

    转自:http://www.cnblogs.com/wengzilin/p/4365855.html 本文主要讨论一下iOS中的Builder Pattern.与网上很多版本不同,本文不去长篇大论地解 ...

  3. 乐在其中设计模式(C#) - 建造者模式(Builder Pattern)

    原文:乐在其中设计模式(C#) - 建造者模式(Builder Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 建造者模式(Builder Pattern) 作者:webabc ...

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

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

  5. 建造者模式(Builder Pattern)

    建造者模式(Builder Pattern) 它可以将多个简单的对象一步一步构建成一个复杂的对象. 意图:将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示. 主要解决:主要解决在软 ...

  6. 二十四种设计模式:建造者模式(Builder Pattern)

    建造者模式(Builder Pattern) 介绍将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示. 示例用同样的构建过程创建Sql和Xml的Insert()方法和Get()方 ...

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

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

  8. 23种设计模式--建造者模式-Builder Pattern

    一.建造模式的介绍       建造者模式就是将零件组装成一个整体,用官方一点的话来讲就是将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示.生活中比如说组装电脑,汽车等等这些都是建 ...

  9. Net设计模式实例之建造者模式(Builder Pattern)

    一.建造者模式简介(Brief Introduction) 建造者模式(Builder Pattern),将一个复杂对象的构建与它的表示分离,使的同样的构建过程可以创建不同的表示. 建造者模式的优点是 ...

随机推荐

  1. HOG算法基础

    实现思路步骤: 1.对原图像gamma校正,img=sqrt(img); 2.求图像竖直边缘,水平边缘,边缘强度,边缘斜率. 3.将图像每16*16(取其他也可以)个像素分到一个cell中.对于256 ...

  2. [LC] 359. Logger Rate Limiter

    Design a logger system that receive stream of messages along with its timestamps, each message shoul ...

  3. python2查找匹配数据及类型转换

    判断一个字符是否包含在另一个字符串中,如果包含,但是数据类型不同,需要进行数据类型转换 下面这个是针对python2

  4. SHELL用法一(基本概念)

    1. SHELL 编程概念入门 1)一个完整 Linux 操作系统(Linux 内核),默认用户是不能直接操作 Linux 内核,需要借助第三方的程序或者软件去操作,例如桌面工具.命令行工具(SHEL ...

  5. OpenResty+缓存穿透基本介绍

    OpenResty                1.lua表达式                 2.Nginx的安装                3.OpenResty              ...

  6. Java中Volatile关键字详解 (转自郑州的文武)

    java中volatile关键字的含义:http://www.cnblogs.com/aigongsi/archive/2012/04/01/2429166.html 一.基本概念 先补充一下概念:J ...

  7. SQLite数据库迁移MySQL(MariaDB)完整步骤

    第一步(SQLite导出数据库): 命令方式导出数据库 > .output d:/data/lagou.sql //导出路径及文件名 > .dump //开始导出 修改lagou.sql文 ...

  8. Myeclipse 错误An internal error has occurred 解决办法

    1. 给MyEclipse的快捷方式加个参数再重新启动一次.      步骤如下:右键选中快捷方式属性选项,在快捷方式页,目标一项最后加上-clean选项,如"C:\MyEclipse6\e ...

  9. WiFi曝出安全漏洞几近“裸奔”:运营商能借机收割一波红利吗?

    ​    作为大众生活中不可或缺的基础架构,也是智能生活普及的推动性力量,运营商的重要性毋庸置疑.但无奈的是,一直以来运营商都似乎是站在了大众的"对立面".看似光鲜亮丽,但在壮观的 ...

  10. linux常用命令使用指南

    <软件自动化测试开发>出版啦 1 系统相关 useradd/userdel   添加用户/删除用户 su      切换用户命令 ls        用于查看所有文件夹的命令 列出目录内容 ...