最近在项目中写bug的时候发现,项目中的公共Dialog管理类是这样的:html
致使每一次增长一种类型的 Dialog 就要增长一个构造函数来实现,长此以往这个类属性也愈来愈多,构造参数的种类也愈来愈多,这个类的初衷是为了封装系统AlterDialog的使用,让一些相一样式的Dialog能够用最简单的样式建立,无奈UI样式随着产品的迭代,愈来愈多,这种单纯的封装有点让人力不从心了。编程
本文将介绍一种简单的设计模式「建造者模式」。也许它能够很好的解决生产中相似上述描述的状况。设计模式
我所理解的设计模式思想,自己就是用于解决重复代码封装的一种思想。是前辈们给咱们留下的经验。而「书本中的建造者模式」是下边的下边这样子的:ide
能够看出设计模式由四部分组成:函数
下面经过一个抽象派的 Dota 英雄建立过程,来看下上述四部分是怎么工做的:学习
首先定一个 DotaHero
类这个类是咱们最终的产品类也就是 Product,他能够理解为一个超类,具体实现决定于建造者如何建造。ui
public class DotaHero { //英雄分类 智力 力量 和 敏捷 public static final int HERO_INTELLECTUAL = 1; public static final int HERO_POWEER = 2; public static final int HERO_AGLIE = 3; @IntDef(value = {HERO_AGLIE, HERO_POWEER, HERO_INTELLECTUAL}) public @interface HeroType { } //英雄属性 private String heroName; private String heroDes; private int heroType; private HashMap<String, String> heroSkills; //施放置顶技能 public void executeSkill(String key) { if (heroSkills.containsKey(key)) { System.out.println("施放 " + key + " 技能: " + heroSkills.get(key)); } } ..... //省略不少的get set } 复制代码
DotaHero 是建造者建造的目标,这里定义的属性和方法是最全的,不一样的建造者,经过不一样的构建步骤,为属性赋值获得最终的不一样英雄。this
下面咱们来定一个一个抽象的建造者建立类,该类定义了全部建造者须要的属性,实现类能够任意扩展。spa
public abstract class HeroBuilder { //最终建造的对象 protected DotaHero hero; public HeroBuilder() { //这里在构造函数中就初始化了对象,其实最好的方法是将其放到build方法中。 hero = new DotaHero(); } public HeroBuilder setHeroName(String name) { hero.setHeroName(name); return this; } public HeroBuilder setHeroDes(String des) { hero.setHeroDes(des); return this; } public HeroBuilder addHeroSkill(String keyName, String skill) { hero.addHeroSkill(keyName, skill); return this; } //定义了英雄类型的抽象方法,须要子类去实现 protected abstract HeroBuilder setHeroType(); public DotaHero build() { return hero; } } 复制代码
接下来咱们来定义Dota中的英雄建造者,你们都知道,Dota 中英雄有 智力,敏捷,力量三种,因此咱们这里定义三种建造者用来构建者三种类型的英雄。设计
//智力 public class AglieHeroBuilder extends HeroBuilder { @Override protected HeroBuilder setHeroType() { hero.setHeroType(DotaHero.HERO_AGLIE); return this; } } //敏捷 public class IntellectualHeroBuilder extends HeroBuilder { @Override protected HeroBuilder setHeroType() { hero.setHeroType(DotaHero.HERO_INTELLECTUAL); return this; } } //力量 public class PowerHeroBuilder extends HeroBuilder { @Override protected HeroBuilder setHeroType() { hero.setHeroType(DotaHero.HERO_POWEER); return this; } } 复制代码
上述列举了三种建造者,这里只作了抽象方法的实现,实际生产中,子类能够根据须要拓展独有属性。
完成上述工做后,咱们就已经可以使用建造者来建立咱们须要的对象了。但建造者模式中推荐咱们将实际对象的生产的工做不要暴露给客户端,须要经过建立者(建立建造者的类)来隔离建造者和客户端,这样客户端只须要声明我须要一个什么样的建造者,来建立一个什么样的对象就能够了。这样当之后出现了新的建造者类型的时候,客户端仍旧只须要关注上述两点。
下面咱们来看下建立者的定义:
public class Director { private HeroBuilder builder; //构造函数1 直接在外界定义好某类型的 Builder 传入 public Director(@NonNull HeroBuilder builder) { this.builder = builder; } public DotaHero getAHero() { if (builder != null) { return builder.build(); } return null; } } 复制代码
上述代码暴露的个构造方法来建立建造者。他目前所作的工做就是获取建造者或者根据类型建立建造者,经过getAHero方法来得到一个生产对象。
经过上述的例子咱们能够很好的理解,第一部分建造者模式的各组成部分的做用以及意义。那么在实际生产过程当中咱们什么时候该应用建造者模式呢?
在如下状况下可使用建造者模式:
建造者模式的意义在于,建造者模式是一步一步建立一个复杂的对象,它容许用户只经过指定复杂对象的类型和内容就能够构建它们,用户不须要知道内部的具体构建细节。
##建造者模式的优缺点
建造者模式的优势:
在建造者模式中, 客户端没必要知道产品内部组成的细节,将产品自己与产品的建立过程解耦,使得相同的建立过程能够建立不一样的产品对象。
每个具体建造者都相对独立,而与其余的具体建造者无关,所以能够很方便地替换具体建造者或增长新的具体建造者, 用户使用不一样的具体建造者便可获得不一样的产品对象 。
增长新的具体建造者无须修改原有类库的代码,建立者类针对抽象建造者类编程,系统扩展方便,符合“开闭原则”。
建造者模式的缺点:
经过上文的叙述相信你们已经知道什么是建造者模式了,咱们也清楚了建造者模式定义步骤,可是实际开发中,若是一个产品类,变化的范围仅仅是属性不一样或者构造顺序不一样,那么一个建造者实现类就能够完成工做,那么咱们能够省略后两个角色,也就是说 Builder 的类兼职完成步骤2和步骤3。
学习设计模式,笔者认为最好的学习方法就是应用,本文中列举的例子可能过于简单,离掌握还差的远,下一片文章将会带领你们了解我对我司项目中 Dialog 建立封装的过程,从实践中来理解。
参考连接: