您的位置:首页 > 产品设计 > UI/UE

Android 内功心法(1.10)——android常用设计模式之建造者(Builder)模式

2016-05-20 10:02 579 查看
目的:

如果你的对象相对复杂,那么就应该考虑对象的构建和它的表现相分离。目的是为了同样的构建过程可以创建不同的表示。

在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源码中用到的设计模式就是最终形态。它也只是在适合的场景用到了适合的设计模式。

它代表的是最合适的场景+最合适的代码方式;并非最好的设计模式的具体体现。

认清真相很重要,做对很重要。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: