Android 内功心法(1.10)——android常用设计模式之建造者(Builder)模式
目的:
如果你的对象相对复杂,那么就应该考虑对象的构建和它的表现相分离。目的是为了同样的构建过程可以创建不同的表示。
在android中我们创建dialog的时候就是建造者模式的最好体现。
AlertDialog alertDialog = new AlertDialog.Builder(getContext()).setView(new EditText(getContext())).create();
我们先来看看android源码中实现builder模式是如何实现的,这里我借鉴朋友的博客java设计模式——-Builder模式里面的一个构建复杂数据的例子来说明:
public class NutritionFacts { private int servingSize = 0; // 食用份量 private int servings; // 份数 private int calories; // 卡路里 private int sodium; // 钠 private int fat; // 脂肪 private int carbohydrate; // 碳水化合物 public static class Builder { private int servingSize = 0; // 食用份量 private int servings; // 份数 private int calories; // 卡路里 private int sodium; // 钠 private int fat; // 脂肪 private int carbohydrate; // 碳水化合物 public Builder(int servingSize, int servings) { this.servingSize = servingSize; this.servings = servings; } public Builder calories(int calories) { this.calories = calories; return this; } public Builder sodium(int sodium) { this.servingSize = sodium; return this; } public Builder fat(int fat) { this.fat = fat; return this; } public Builder carbohydrate(int carbohydrate) { this.carbohydrate = carbohydrate; return this; } public NutritionFacts show() { return new NutritionFacts(this); } } private NutritionFacts(Builder builder) { servings = builder.servings; servingSize = builder.servingSize; calories = builder.calories; carbohydrate = builder.carbohydrate; fat = builder.fat; sodium = builder.sodium; }}
这就是类似android源码中dialog的builder模式,我们用这种方式去创建一个复杂的数据结构是非常简单和方便的。
调用方法:
NutritionFacts nutritionFacts = new NutritionFacts .Builder(20, 8) .calories(20) .carbohydrate(50) .fat(60) .show();
这个数据结构是不是很想android中new一个AlertDialog的写法?
我们去翻看AlertDialog源码你就会发现,其实是一模一样的写法。
这样得到的nutritionFacts实例你可以实现部分数据,也可以实现全部数据。
but!
如果你觉得这就是builder模式了,那你就太小看它的魅力了。
以上代码只是一个简单的示范,我要说的是builder模式的实现原理和工作方式。
在我看来以上这种builder模式是最简单的但并非最好的。
以上代码适合一个房子的建造,比如AlertDialog。如果你在建立一个AlertDialogA或者AlertDialogB。建立一个类似的房子的时候是不是需要重新写一个AlertDialogA或者AlertDialogB的代码呢?
所以,以上代码是有问题的。
第一,强耦合;
第二,必须声明静态;
第三,不符合开闭原则。
首相我们要搞清楚一个builder模式需要什么东西。
1,一个需要被建造出来的对象。比如房子。(dialog)
2,一个建造房子的工人。(builder)
3,指挥工程师如何建房子的工程师。比如指挥者。(director)
4,一个对象的建造,哪些是必须的,哪些是非必须的。就像一栋房子的房梁,墙体,房顶,这是必须的。但是贴瓷砖、建围墙、装修豪华这些是非必须的。
只要一个builder模式完成了这四个部分,那么你再造一栋房子,不用重复了,只需要在原来做过的这栋房子上稍加改造就行了。
具体看代码实现吧。
/** * 抽象建造者类,包含一个建造者必须建造的具体产品,还有一些制造产品的零件,零件不是必须的。 */public abstract class Builder { public abstract void buildPartA();//零件a public abstract void buildPartB();//零件b public abstract void buildPartC();//零件c public abstract Product getPart();//得到由建造者建造的具体产品}
/** * 建造者具体实现类 */public class ConcreteBuilderA extends Builder { private Product product = new Product(); @Override public void buildPartA() { product.addPart("这个产品必须的零件a"); Log.i("test", "制造零件a"); } @Override public void buildPartB() { product.addPart("这个产品必须的零件b"); Log.i("test", "制造零件b"); } @Override public void buildPartC() { product.addPart("这个产品必须的零件b"); Log.i("test", "制造零件c"); } //返回一个制造出来的具体产品 @Override public Product getPart() { return product; }}
/** * 指挥者类 * 指挥者决定让建造者必须建造哪些零件 * 相当于指挥者对建造者说,房梁,墙体,房顶,必须建造 */public class Director { public void cunstruct(Builder builder) { builder.buildPartA();//创建零件a builder.buildPartB();//创建零件B //builder.buildPartC();//创建零件C,这栋房子不需要零件c }}
/** * 产品类,由多个零件组成; * 一个产品可以添加很多的属性,这些属性不是必须的 * 就相当于一个基本完成的房子包含好多操作:刷墙,贴瓷砖,装修、建立围墙 * 这些操作不是必须的 */public class Product { List<String> parts = new ArrayList<>(); public void addPart(String part) { parts.add(part); } public void getPartTile(String title) {//得到由建造者建造的名称 Log.i("test", "设置产品标题"); } public void getPartMessage(String message) {//得到由建造者建造的简介 Log.i("test", "设置产品介绍"); } public Button getPartButton(Button button) {//得到由建造者建造的操作按钮 return button; } //将这个产品类展示出来,房子完工 public void show() { for (String part : parts) { Log.i("test", part); } }}
到这里。已经完工了。
1,抽象建造者控制必须建造的方法。(老板。这里的一切我说了算)
2,具体建造者(工人)执行建造。
3,指挥者(工程师)决定建造者建造哪些方法。
4,产品类。所有的老板,工人,工程师都是围绕着如何建立这个产品而生的。
我们来看看使用方法:
Director director = new Director();//实例化一个指挥者 Builder builder = new ConcreteBuilderA();//实例化一个建造者 director.cunstruct(builder);//指挥者告诉建造者你必须要建造哪几个类,必须创建的类是抽象建造者中包含的抽象方法,而指挥者告诉建造者,这部分的抽象方法必须实现,因为这是必不可少的。 Product product = builder.getPart();//具体要建造的产品,它其中有很多方法,这些方法可以全部实现,也可以部分实现 product.addPart("非必需零件a"); product.addPart("非必需零件b"); product.getPartMessage("这是一个dialog"); product.getPartTile("dialog的标题"); product.getPartButton(new Button(context)); product.show();
这种builder比较复杂,但是它的确符合设计模式的六大原则。
如果你用这中方式创建一个AlertDialog。那么你同样可以用这中方式创建一个AlertDialogA或者更多类似的产品。
我们只需要在抽象建造者类中控制所有必须方法。
然后再创建一个工程师,称之为建造AlertDialogA的工程师,它告诉BuilderA(AlertDialogA的工人)建造AlertDialogA的必须方法。
再创建一个工人,称之为AlertDialogA的工人。完成工程师交代的任务。
最后,拿出ProductA产品的蓝图。
test,开工!
代码没有重复,没有修改原来建造的AlertDialog,相反拓展了AlertDialogA的创建方式。
这才是一个合格的或者说最好的设计模式实现方法。
这里要说明的一点是,并非android源码中用到的设计模式就是最终形态。它也只是在适合的场景用到了适合的设计模式。
它代表的是最合适的场景+最合适的代码方式;并非最好的设计模式的具体体现。
认清真相很重要,做对很重要。
更多相关文章
- android Activity 四大启动模式探究
- Activity中的四种启动模式
- Android Activity的四种加载模式
- JAVA数据结构及算法--Android中Activity的四种启动模式
- Android上的Open×××-TAP模式/策略路由
- Android飞行模式下Wifi开关行为的控制
- Android WindowManager的使用 & 添加 遮罩层 实现夜间模式
- Android情景模式、文件管理器 完整示例编程详解、Android程序优