前言

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

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

什么是建造者模式

首先建造者模式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. Chrome开发者调试工具

    参考资料 Chrome Console不完全指南 Chrome使用技巧 Chrome开发工具详解 结束语 工欲善其事,必先利其器.

  2. Android Studio调用系统隐藏接口EthernetManager

    google source签名文件参考:https://android.googlesource.com/platform/build/+/donut-release/target/product/s ...

  3. 如果你的unordered_map头文件报错请看这里

    请将include<unordered_map>头文件换成下面代码 #if(__cplusplus == 201103L) #include <unordered_map> # ...

  4. [转]<版本一>写代码的小女孩

    天冷极了,下着雪,又快黑了.这是NOIP的前夜.在这又冷又黑的晚上,一个衣衫破烂的小女孩在机房敲着代码.她从班里逃出来的时候还拿着一本算导,但是有什么用呢?那是一本很破旧的书——那么大,一向是她妈妈垫 ...

  5. js javascript 获取url,获得当前页面的url,静态html文件js读取url参数

    获得当前页面的url window.location.href 静态html文件js读取url参数 location.search; //获取url中"?"符后的字串 下边为转载的 ...

  6. PyCharm 介绍、安装、入门使用

    一.Pycharm介绍 前面几年的时间,我一直用的eclipse,后面开始听同事说用IntelliJ IDEA了,而且说是目前业界最好用的java开发工具,IDE(集成开发环境),没有之一.PyCha ...

  7. loadrunner没有告诉你的

    1.        LoadRunner之-Block l  如何在一个脚本中实现不同事务不同次数的循环呢? l  案例:假如你想在一个脚本中,实现登录执行1次,查询执行2次,插入执行3次,怎么办?录 ...

  8. ES介绍与实践

    一.ES介绍 1.基础概念介绍 1. 索引:Elasticsearch中的“索引”有点像关系数据库中的数据库. 它是存储/索引数据的地方: 2.分片 shard “分片”是Lucene的一个索引. 它 ...

  9. Leetcode 20题 有效的括号(Valid Parentheses) Java语言求解

    题目描述: 给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效. 有效字符串需满足: 左括号必须用相同类型的右括号闭合. 左括号必须以正确的顺序闭合. 注意空 ...

  10. CSS——NO.5(格式化排版)

    */ * Copyright (c) 2016,烟台大学计算机与控制工程学院 * All rights reserved. * 文件名:text.cpp * 作者:常轩 * 微信公众号:Worldhe ...