前言
最近看了陈宇明老哥的英雄联盟之「策略模式」和王者荣耀之「装饰者模式」。作为日常上王者的我看完以后还是很惊(bu)喜(xie)的。什么?日常上王者不知道什么意思?
直接上图:
淡定淡定.. 其实我也不想上王者的,都是队友太给力了,所以每次我都带他们躺赢 :)
好了不催牛X了,进入本文的主题:王者荣耀之「建造者模式」
首先我们了解一下什么是建造者模式
Builder模式是一步一步创建一个复杂的对象的创建型模式,他允许用户在不知道内部构建细节的情况下,可以更精确的控制对象的构造流程。该模式是为了将构建复杂对象的过程和它的部件解耦,是的构建过程和部件的表示隔离开来。
在这里我举一个栗子,就好比王者荣耀中展示一个英雄的效果需要人物技能、回城的效果和皮肤。这里就可以使用Buidler建造者模式将他们和组装过程分离,使得构建过程和部件都可以自由扩展,两者之间耦合可以降到最低。
Builder模式的定义
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
在这里为什么用Builder模式呢
1.因为他具有良好的封装性,可以使客户端不用知道产品内部组成的细节
2.建造者独立,容易扩展
经典的Builder模式主要有四个参与者:
- Product:被构造的复杂对象
- Builder:抽象接口
- ConcreteBuildr:Builder接口的具体实现
- Director:Builder接口的构造者和使用者
目前来说在Android&Java开发过程中经典的Builder模式使用的较少,一般广泛使用的是他的一个变种,这里就不详细的讨论经典的Builder模式了一下讨论的都是变种的Builder模式。
在我们日常开发的过程中,变种Builder模式很常见。举个栗子,在android源码中最常用到的Builder模式就是AlertDialog.Builder,使用该Builder来构建复杂的AlerDialog对象。另一个栗子就是Glide,他的底层实现就用到了Glide
Glide.with(this)
.load(R.raw.large_giphy_logo)
.into(giphyLogoView);
还有就是我们常用的通知,由于通知中会有很多的内容,通过建造者模式可以很方便的来展示需要展示的内容
上图则是一个通知中包含了大图标、小图标、标题和内容。通知栏的内容很丰富,如下是想要构造一些其他的内容:
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this)
.setContentTitle("标题")//设置通知栏标题
.setContentText("内容") //设置通知栏显示内容
.setContentIntent(getDefalutIntent(Notification.FLAG_AUTO_CANCEL))//设置通知栏点击意图
.setNumber(number) //设置通知集合的数量
.setTicker("通知到来") //通知首次出现在通知栏,带上升动画效果的
.setWhen(System.currentTimeMillis())//通知产生的时间,会在通知信息里显示,一般是系统获取到的时间
.setPriority(Notification.PRIORITY_DEFAULT) //设置该通知优先级
.setAutoCancel(true)//设置这个标志当用户单击面板就可以让通知将自动取消
.set(...其他的就不举例了)
等收到通知的时候通过mBuiler.builder来创建
接下来通过王者荣耀的例子带大家熟悉一下 建造者模式
首先给没有玩过王者荣耀的普及一下知识:
在这里我们来建造一个英雄,首先要设计这个英雄的3个技能
然后设置他的攻击方式,默认是近战攻击
然后建造他的皮肤,不进行建造皮肤的时候使用它的默认皮肤,
然后是回城效果。
行了,介绍差不多了来撸码吧。
本篇的Demo就是一个链式的建造者模式的简单实现,首先实现一个引用配置类:
public class HeroConfig {
HeroBuilder mBuilder = null;
//英雄的三个技能
private String firstSkill;
private String secondSkill;
private String thirdSkill;
private String TPeffect = "无回城特效";
private String skin = "普通皮肤";
private String attack = "近战攻击";
public HeroConfig(HeroBuilder builder) {
mBuilder = builder;
init();
}
private void init() {
//这里是判断是否构建,未构建用默认值
if (mBuilder.firstSkill != null) {
firstSkill = mBuilder.firstSkill;
}
if (mBuilder.secondSkill != null) {
secondSkill = mBuilder.secondSkill;
}
if (mBuilder.thirdSkill != null) {
thirdSkill = mBuilder.thirdSkill;
}
if (mBuilder.TPeffects != null) {
TPeffect = mBuilder.TPeffects;
}
if (mBuilder.skin != null) {
skin = mBuilder.skin;
}
if (mBuilder.attack != null) {
attack = mBuilder.attack;
}
}
@Override
public String toString() {
return
"技能1——>" + firstSkill +
" 技能2——>" + secondSkill +
" 技能3——>" + thirdSkill +
" 回城特效——>" + TPeffect +
" 皮肤是——>" + skin +
" 普通攻击属性-->" + attack
;
}
}
在这里写一个HeroConfig 的静态内部类HeroBuilder。这样就可以实现HeroConfig.HeroBuilder的链式写法了,如下:
HeroConfig.HeroBuilder("","","")
.builXX("")
.buildXX("")
.create();
静态内部类HeroBuilder 如下:
public static class HeroBuilder {
//3个技能
private String firstSkill;
private String secondSkill;
private String thirdSkill;
private String TPeffects; //回城效果
private String skin; //皮肤
private String attack; //攻击方式
//在这里扩展一下,由于英雄的三个技能是必选的,而回城的特效、攻击方式和皮肤是可选的
//所以提供一个构造方法在构造的时候一定设置3个技能即可
public HeroBuilder(String firstSkill, String secondSkill, String thirdSkill) {
this.firstSkill = firstSkill;
this.secondSkill = secondSkill;
this.thirdSkill = thirdSkill;
}
public HeroConfig create() {
HeroConfig mHeroConfig = new HeroConfig(this);
return mHeroConfig;
}
public HeroBuilder buildAttack(String attack) {
this.attack = attack;
return this;
}
public HeroBuilder buildSkin(String skin) {
this.skin = skin;
return this;
}
public HeroBuilder buildTPeffects(String effect) {
this.TPeffects = effect;
return this;
}
}
最后在Activity中来构建英雄:韩信、李白、后裔、诸葛亮
HeroConfig 韩信=
new HeroConfig.HeroBuilder("无情冲锋","背水一战","大招!--国士无双")
.buildSkin("白龙吟")
.create();
HeroConfig 李白=
new HeroConfig.HeroBuilder("将进酒","神来之笔","大招!--青莲剑歌")
.buildSkin("凤求凰")
.create();
HeroConfig 后裔=
new HeroConfig.HeroBuilder("炙热之风","燎原箭雨","大招!--一支穿云箭")
.buildAttack("远程攻击")
.buildSkin("阿尔法小队")
.create();
HeroConfig 诸葛亮=
new HeroConfig.HeroBuilder("东风破袭","时空穿梭","大招!--元气弹")
.buildAttack("远程攻击")
.create();
HeroConfig 土豪诸葛亮=
new HeroConfig.HeroBuilder("东风破袭","时空穿梭","大招!--元气弹")
.buildSkin("黄金分割率")
.buildTPeffects("爱心回城特效")
.buildAttack("远程攻击")
.create();
Log.e("韩信", 韩信.toString());
Log.e("李白", 李白.toString());
Log.e("后裔", 后裔.toString());
Log.e("诸葛亮", 诸葛亮.toString());
Log.e("土豪诸葛亮", 土豪诸葛亮.toString());
最后打印的结果如下:
总结
好了这就是变种Builder模式,在Android开发比较常用,通常作为配置类的构建器将配置的构建和表示分离,也就是王者荣耀中的各种技能、特效等,将他们从目标类中隔离出来避免过多的setter方法。通过链式实现使得代码更简洁、易懂。缺点呢就是会产生多余的Builder对象消耗内存,不过这个缺点可以被他的优点所弥补。变种的Builder模式是根据经典的Builder模式在日常开发中的需要延伸出来的一种方式,经典Builder模式UML如下:
现在在日常的开发中Director角色经常会被忽略,这样会相对的减少了构造的步骤而直接使用一个Builder来进行对象的组装,最关键的还是Builder通常为链式调用,它的每个setter方法都返回自身,也就是代码中的return this
,这样就可以实现链式调用了。
最后
本篇的这波操作还可以吧,我觉得可以,本来是准备上传一段诸葛秀操作的视频给大家压压惊,结果第一把保存视频以后不能导出,第二把开了英雄时刻手机没有内存没保存下来... 干脆不录了,想来躺的可以一起农药哇~~ 最后只留下了2把战绩给大家了。。
如果喜欢本文的话,欢迎点击一下 “喜欢” 给予鼓励支持!