亲宝软件园·资讯

展开

我要打十个!详解建造者模式(builder pattern)

二营长的笔记 人气:0
### 前言 “我要打十个”,其实是我要打十个野怪! 这十个野怪呢,它们有不同的技能、装备和武器,长得也不一样。这里野怪是一个蛮复杂的对象,由各个不同的部分组成(技能、装备、武器等),不同的野怪的它们各部分之间的构成方式就不同。因此,要创建这种复杂对象,就需要使用建造者模式。 ### 什么是建造者模式 首先建造者模式Gof 23种设计模式之一。也叫Builder模式。 **是将一个复杂对象的构建和其表示相分离,使得同样的构建过程可以创建不同的表示。** 我们来品一品这句话,首先是复杂对象,这个复杂对象中可能包含了多个不同的其他对象。其次是这个复杂对象的创建一定是用到了这些其他对象,通过一定的算法组合能才创建出这个对象。最后就是它能通过builder创建出一些特性不同但相似的对象。 好了,借用Linus 名言: **Talk is cheap. Show me the code!!!** ![表情包图](https://img-blog.csdnimg.cn/20200317002221427.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzM3OTY1MDE4,size_16,color_FFFFFF,t_70) ### 代码实现 开始创建我们的野怪类,就叫做Hero吧,它的组成部分有技能类Skill,装备类Armor 和武器类Weapon 。 创建Skill、Armor和Weapon类 ```java 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内部类超详细总结(含代码示例)](https://blog.csdn.net/m0_37965018/articlehttps://img.qb5200.com/download-x/details/98457370) ```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,测试一把。 ```java 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); } } ``` 结果如下: ```bash Hero{name='纳什男爵', skill=Skill{skillName='飞龙在天'}, armor=Armor{armorName='亢龙铠甲'}, weapon=Weapon{weaponName='唾沫星子'}} ``` 当然了,这里也可以创建个“四鸟”,“河蟹”之类的。总之,你要打十个,么有问题啊,我们给你builder十个就好了,而且是不重样的。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200317002709336.gif) ### Builder模式在源码中的应用 **StringBuilder** 其实我们熟知的StringBuilder就是builder模式的典型实现。我们平时使用基本都是这样: ```java StringBuilder sb = new StringBuilder(); sb.append(123).append('a') .append(1.23) .append(true) .append("hhhh"); ``` 看着就很平常,soeasy的感觉,其实可以看到它能添加不同的数据类型进去,对应建造者模式中的各个部分,通过append方法的不同组合构建出了不同的StringBuilder对象。 看下源码: ```java ...... @Override public StringBuilder append(boolean b) { super.append(b); return this; } @Override public StringBuilder append(char c) { super.append(c); return this; } ...... ``` 上面列举了两个重载方法,可以看到其实是调用了父类的重载方法,父类是AbstractStringBuilder ```java // 这里只列举这一个父类的方法 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 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200316234910657.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzM3OTY1MDE4,size_16,color_FFFFFF,t_70) 所有的build重载方法都在构建SqlSessionFactory 对象。只是可以根据需要调用不同的方法,传入不同的参数,就可以构建出特性不同的SqlSessionFactory 。 看下其中一个build方法的源码 ```java ...... 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面试必备:手写单例模式](https://blog.csdn.net/m0_37965018/articlehttps://img.qb5200.com/download-x/details/93791567) [工厂模式超详解(代码示例)](https://blog.csdn.net/m0_37965018/articlehttps://img.qb5200.com/download-x/details/103152585) [设计模式之原型模式](https://blog.csdn.net/m0_37965018/articlehttps://img.qb5200.com/download-x/details/103192446) [设计模式之代理模式](https://blog.csdn.net/m0_37965018/articlehttps://img.qb5200.com/download-x/details/103229235) [设计模式之委派模式,大名鼎鼎的Spring都在用](https://blog.csdn.net/m0_37965018/articlehttps://img.qb5200.com/download-x/details/104867063) >公众号:二营长的笔记 >免费领资料:公众号内回复“二营长”

加载全部内容

相关教程
猜你喜欢
用户评论