前言
其他创建型模式:
- AbstractFactory (抽象工厂)
- FactoryMethod(工厂方法)
- Prototype(原型模式 )
- Singleton(单例模式)
今天来介绍创建型模式之Builder(生成器)。Builder模式在Android开发中我们遇到很多,无论是平时的开发,还是在阅读Android源码的过程都会遇到。例如Android源码中:
- app核心层: Notification.Builder(android.app)
- 图形绘制层:TypeFace.Builder(android.graphics)
- 底层硬件层:BluetoothDeviceFilter.Builder(android.companion)
- 网络层:Uri.Builder(android.net)
可以发现,在Android的源码框架中,Builder模式的运用真的是非常普遍。
大家可以通过快捷键在Android源码当中搜索Builder即可。最常见的就是AlertDialog.Builder对象,如下图所示:
可以看到这么多方法才使得我们在coding时去create一个Dialog对象的时候才能随心所欲,Android中创建Dialog的这种方式,充分的体现了Builder模式的强大和灵活。
接下来我们来具体学习Builder模式:
1. 意图
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
2. 适用性
- 当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时。
- 当构造过程必须允许被构造的对象有不同的表示时。
3. 参与者
- Builder —— 为创建一个Product对象的各个部件指定抽象接口。
- ConcreteBuilder
—实现Builder的接口以构造和装配该产品的各个部件。
— 定义并明确它所创建的表示。
— 提供一个检索产品的接口。 - Director —— 构造一个使用Builder接口的对象。
- Product
— 表示被构造的复杂对象。ConcreteBuilder创建该产品的内部表示并定义它的装配过程。
— 包含定义组成部件的类,包含将这些部件装配成最终产品的接口。
4. 效果
1)它使你可以改变一个产品的内部表示时
2)它将构造代码和表示代码分开
3)它使你对构造过程进行更精细的控制
5. 实例
我们还是以汽车为例子,
汽车一般一共由五大部分组成:
- 发动机(Engine)
- 传动系统(Power)
- 车身(body)
- 转向(Steering)
- 悬挂(Suspension)
那么就可以抽象出对应的Builder接口:
CarBuilder.java
public interface CarBuilder {
/**
* 构建发动机
*/
void buildEngine();
/**
* 构建传动系统
*/
void buildPower();
/**
* 构建车身
*/
void buildBody();
/**
* 构建转向
*/
void buildSteering();
/**
* 构建悬挂
*/
void buildSuspension();
Car buildCar();
那么对应的参与者Product就是汽车本身,这里我们以宝马和奥迪来进行举例:
对应的 ConcreteBuilder 就是AudiBuilder和BmwBuilder,如下图
然后需要一个Director的角色来指导不同的Car的构建:
CarDirector.java
public class CarDirector {
public Car buildCar(CarBuilder carBuilder) {
carBuilder.buildBody();
carBuilder.buildEngine();
carBuilder.buildPower();
carBuilder.buildSteering();
carBuilder.buildSuspension();
return carBuilder.buildCar();
}
}
最后我们来测试一下:
private static void testBuilder() {
CarDirector carDirector = new CarDirector();
//构建奥迪车
final Car audiCar = carDirector.buildCar(new AudiCarBuilder());
System.out.println(audiCar.toString());
//构建宝马车
final Car bmwCar = carDirector.buildCar(new BmwCarBuilder());
System.out.println(bmwCar.toString());
}
测试结果下图所示:
实践完汽车的这个简单的实例,我们再来看一下Android中经典的Builder模式之AlertDialog.Builder:
//很经典的链式调用有木有(一气呵成)
AlertDialog dialog = new AlertDialog.Builder(this)
.setTitle("title")
.setMessage("message")
.create();
dialog.show();
通过阅读AlertDialog.Builder源码,可以看出Builder类是属于AlertDialog类的一个静态内部类,由源码过多,我们只分析部分构建过程:
public class AlertDialog extends Dialog implements DialogInterface {
//.....此处省略若干行代码
public static class Builder {
private final AlertController.AlertParams P;
public Builder(Context context) {
this(context, resolveDialogTheme(context, ResourceId.ID_NULL));
}
public Builder setTitle(@StringRes int titleId) {
P.mTitle = P.mContext.getText(titleId);
return this;
}
public Builder setMessage(CharSequence message) {
P.mMessage = message;
return this;
}
public AlertDialog create() {
//构建一个新AlertDialog对象,并通过AlertController.AlertParams配置Dialog
final AlertDialog dialog = new AlertDialog(P.mContext, 0, false);
P.apply(dialog.mAlert);
dialog.setCancelable(P.mCancelable);
if (P.mCancelable) {
dialog.setCanceledOnTouchOutside(true);
}
dialog.setOnCancelListener(P.mOnCancelListener);
dialog.setOnDismissListener(P.mOnDismissListener);
if (P.mOnKeyListener != null) {
dialog.setOnKeyListener(P.mOnKeyListener);
}
return dialog;
}
public AlertDialog show() {
final AlertDialog dialog = create();
dialog.show();
return dialog;
}
//.....此处省略若干行代码
}
}
和构造汽车的Builder模式相比较,AlertDialog.Builder缺少了Director角色,但是这并不影响Builder模式的效果,其精髓之处就是体现在程序员一步步构建Dialog对象的时候,其实也可以把具体使用Dialog情景或者方法体看成是一个虚的Director。
第三方库中Builder的使用
另外Builder的构建经常在静态工厂的构建对象或者作为第三方库使用的时候出现,比如知乎开源的一个强大图片选择器Matisse
在使用Matisse的时候就是经典的链式调用+Builder模式,这里Matisse本身其实就是 Builder !!!
Matisse.from(MainActivity.this)
.choose(MimeType.allOf())
.countable(true)
.maxSelectable(9)
.addFilter(new GifSizeFilter(320, 320, 5 * Filter.K * Filter.K))
.gridExpectedSize(getResources().getDimensionPixelSize(R.dimen.grid_expected_size))
.restrictOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)
.thumbnailScale(0.85f)
.imageEngine(new GlideEngine())
.forResult(REQUEST_CODE_CHOOSE);
大家有兴趣可以去阅读以下它的源码,另外这里面还应用了其他模式,例如代理模式、模板方法等,这里会在后续的文章进行介绍。
6. 总结
Abstract Factory与Builder相似,因为它也可以创建复杂对象。主要的区别就是Builder模式着重于一步步构造一个复杂的对象。而Abstract Factory着重于多个系列产品的对象的构建。Builder在最后一步产品返回的时候,对于Abstract Factory来说,产品是立即返回的。