问题思考
设计一个网络库,那么访问的Url是所必须的参数。其他参数诸如Http Header、请求超时、链接超时、请求方法、回调响应结果等都属于非必须参数。那么如何设计才能告诉使用者Url是必须的而其他参数是可选的。
为了让大家更能简单理解,贴近自然。以人举例,人的生存所必须的三个物质是 空气、水、食物。至于衣服、金钱、girl、game等其实都是非必须的。那如何告诉女娲呢?
解决思路一 重叠构造函数
我们知道,良好命名的函数参数以及注释能够很好的告诉使用者 “我需要哪些参数,哪些是必须的” 那如果实现创建人的功能及拓展功能,代码大概是存在参数必须的构造函数,还有其他附加功能的构造函数。假设有3个附加功能选项,组合起来有多少种可能。2的3次方-1 = 7种 !如果附加项功能有10个呢 ? 那种代码量和复杂度是相当可怕的,代码看起来是这样的。
图中展示了另外一个很重要的问题 - 当同名方法的参数个数,类型,顺序一致时无法被重写。编译器会告诉你函数重复了。
综上我们看到利用构造函数迭代,无法优雅的解决需求,甚至有弊端。
解决思路二 JavaBean
很多同学一定会想到,既然重叠构造器不行,那么我利用JavaBean的设置,来灵活的设置人的属性就可以了。利用JavaBean来解决的代码大概是Person 的必须和非必须成员变量实现了getter和setter 调用代码是这样子的
这样解决了多个构造器产生的一系列问题,但这样就优雅了么,否!
问题有两点
1. 无法很好的限制及告诉使用者哪些是必要参数
有人会说,那我提供一个必要参数的构造函数,文档上注明。那可不是优雅的办法,兄弟~
有人会说,那我利用简单工厂模式,设置一个人的默认实现,兄弟,你很灵醒啊,的确是可以的,但我觉得使用Builder来做更适合,这里不做讨论。其实模式本身就很灵活,半用,衍变用,结合用,用到随心所欲才是大成境界。
2.JavaBean在程序运行中无法保证状态不被修改,一旦被修改在最终调用时假设报错了,很难查找原因
我想大家在做Listview的时候,也许遇到过没有维护好数据源,导致在程序运行中数据源非正常改变,数据列表不正确的事情。这足矣说明我们内存中的数据无意间变了,对于查找问题是相当困难的。如果要使用JavaBean解决问题,首要考虑的就是线程安全问题,保证其合理运行中被“冻结”
思路三 利用Builder建造器代替构造函数
首先看下我们十分熟悉的Universal-Image-Loader的初始化代码
哇,看到后是否觉得这种方式十分优雅!的确,目前很多第三方库的对象创建都采用这种方式,你想想还看到过哪些?
那么对于本文中创造人代码如何去做呢?如下
Person类里面有一个静态内部类Builder,Person的构造函数为私有,防止被外部创建。把真正创建Person对象的方法放在Builder内。我们看下Builder
第一 提供默认必须参数的构造器,这是人生存的三种必需品
第二 每个附加功能衣服,金钱,女人的方法返回Builder对象,这样代码上可以完成链式调用
第三 build() 创建真正的对象
本质
Builder模式本质 分离整体构建算法和部件构造
结束语
如果类的构造函数含有多个多参数时,特别是大多数参数是可选的,设计这种类时,Builder模式就值得使用。它比传统的重叠构造函数相比代码更少,使用者更易读,出错后查找简单,另外Builder比JavaBean的方式更加安全。