参考:
- 经典 Builder / 变种 Builder 模式及自动化生成代码插件
- 变种 Builder 模式:优雅的对象构建方式
- 《Android源码设计模式解析与实战》
- 重学设计模式 – 建造者模式
- 王者荣耀之「建造者模式」
- 结合 Android 浅谈 Builder 模式
- 人人都会设计模式—建造者模式–Builder
前言
builder模式也叫建造者模式, 也是Android中应用十分广泛的设计模式之一.
举个例子, 比如我们经常使用的框架okhttp和retrofit
1 | OkHttpClient client = new Builder().writeTimeout(10, TimeUnit.SECONDS) |
1 | Retrofit retrofit = new Retrofit.Builder().baseUrl(BASE_URL) |
还有Android中AlerDialog
1 | new AlertDialog.Builder(this).setTitle("这是标题") |
所以我们赶快去探究一下这神器的builder模式吧
Builder模式介绍
该模式是为了将构建复杂对象的过程和它的部件解耦, 构建过程和部件都可以自由扩展, 降低耦合.举例来说, 如果一个类有很多种构造方法, 或者一个构造方法中需要传入很多的参数, 比如说需要十几个参数, 可想而知这样的构造函数是十分容易出错的.而如果使用set方法来依次传入参数, 又失去了链式调用的优雅性, 代码变得不连续.这个时候使用builder模式就非常适合了.
Builder模式的UML类图
这时候又要再次科普一下UML类图中各种图形的含义了(因为我每次都容易忘记).
每个矩形都代表一个类(包括class和interface), 比如中间的那个Builder, 第一层显示它的类名是Builder, 顶端的《abstract》
表示这是一个抽象类, 第二层表示它有三个方法, ‘+’表示方法是public的, 三个方法的返回类型都是void.
空心三角形 + 实线 表示ConcreteBuilder是继承自Builder的
箭头 + 虚线 表示依赖关系, 箭头指向被使用者, 比如这里的意思就是说ConcreteBuilder依赖Product, 因为ConcreteBuilder在组装的时候还是需要一个Product的, 不然它把零件组装到哪里去呢?也就是说ConcreteBuilder持有Product的引用.
空心菱形 + 实线(或者箭头线) 表示聚合关系, 汽车对象由轮胎对象聚合而成,但是轮胎对象的生命期并不受汽车对象的左右。当汽车对象销毁时,轮胎对象也可以单独存在.在这里, Director中必定有一个变量能够指向Builder, 表示聚合关系.
经典的Builder模式
Product
1 | /** |
具体的Product
1 | /** |
抽象Builder
1 | /** |
ConcreteBuilder
1 | /** |
Director
1 | /** |
测试代码
1 | public class Main { |
输出结果:
1 | Computer Info: Computer{mBoard='英特尔主板', mDisplay='Retina 显示器', mOS='Mac OS X 10.10'} |
可以看出, 经典的 Builder 模式重点在于抽象出对象创建的步骤,并通过调用不同的具体实现类从而得到不同的结果, 但是在创建过程中依然要传入多个参数, 不是很方便, 所以有了变种的Builder模式
变种的Builder模式
目前来说在 Android&Java 开发过程中经典的 Builder 模式使用的较少,一般广泛使用的是他的一个变种.
在日常的开发中 Director 角色经常会被忽略,这样会相对的减少了构造的步骤而直接使用一个 Builder 来进行对象的组装.
这里我要说的就是一种内部Builder并且能够链式调用的变种.
我们就直接进入实战, 模仿AlertDialog写一个dialogfragment, 但是比AlertDialog更简单些.
1 | /** |
现在在日常的开发中 Director 角色经常会被忽略,这样会相对的减少了构造的步骤而直接使用一个 Builder 来进行对象的组装,最关键的还是 Builder 通常为链式调用,它的每个 setter 方法都返回自身,也就是代码中的 return this, 这样就可以实现链式调用了。
使用EasyDialogFragment:
1 | DialogFragment dialogFragment = new Builder().setTitle("这是标题") |
效果:
总结
最后总结一下builder模式的优缺点
优点:
- 良好的封装性, 使用建造者模式可以使客户端不必知道产品内部组成的细节
- 建造者独立, 容易扩展
- 链式调用使得代码更简洁、易懂
缺点:
会产生多余的builder对象以及Director对象, 消耗内存
最后
最后发现了一个自动生成builder模式的插件 InnerBuilder
详细可以看这篇
本文代码地址:
https://github.com/mundane799699/AndroidProjects/tree/master/BuildDesignPattern