静态工厂和构造器有个共同的局限性:它们都不能很好地扩展到大量的可选参数。
应用场景示例:
当一些业务场景中,往往在构建一个类的对象时,要求构建该对象属性时是可选的。如一个类表示包装食品外面显示的营养成分标签。这些标签
中有2个必选的:含量,卡路里。还有超过20个可选的:总脂肪量、饱和脂肪量、胆固醇、蛋白质等。不同的产品的营养成分中均有必选成分,但可选的不同产品所需展示的不同。在这样的情况下,客户端如果根据不同的产品来构建营养成分标签呢?
1.重叠构造器方式:第一个构造器提供一个必要参数的构造器,第二个构造器提供一个可选参数,第三个有两个可选参数,依次类推,最后一个构造器包含所有可选参数。
如下示例:
客户端代码可以选择性地调用构造器来满足不同场景。但也存在问题:
a. 这个构造器调用通常需要许多不想设置的参数,但还是不得不为它们传递值。
b. 当有许多参数的时候,客户端创建示例的代码会很难编写,并且难以阅读。
2.JavaBeans方式:调用一个无参构造器来创建对象,然后调用setter方法来设置每个必要的参数,以及所需的可选参数。
如下示例:
这种模式相比于重叠构造器来说,创建示例很容易,产生的代码也容易读。
遗憾的是,JavaBeans方式自身有着很严重的缺点:由于整个对象的构建被分到了几个调用中,在构造过程中JavaBean可能处在不一致的状态。类无法仅仅通过检验构造器参数的有效性来保证一致性。如果想要保证一致性,需要程序员付出更多的努力来实现。
3. 构建器:不直接生成想要的对象,而是让客户端利用所有必要的参数调用构造器,得到一个builder对象。然后客户端在builder对象上调用类似与setter的方法,来设置每个相关的可选参数。最后,客户端调用无参的build方法来生成不可变的对象。
如下示例:
先调用类的builder必要参数的构造创建一个builder,再用setter设置各个可选参数(注意使用return this;可以构造参数链),最后调用builder方法返回一个构建好的对象
构建器的好处:
a) Builder像个构造器,可以在builder方法中对象域里对其参数强加约束条件。也可以在builder的setter方法中加约束条件,当校验失败则抛出异常,取消了对象的整个构建。
b) Builder可以有多个可变参数
c) Builder方法可以自动填充域,也可以返回不同的对象
d) 使用泛型的builder,JDK1.5及以后的版本提供了Builder接口。
e) Java传统的抽象工厂实现是Class对象,用newInstance()来build。
评价:newInstance()会主动调用无参数的构造函数,而且没有编译时错误,只能在runtime抛出异常。这破坏了编译时的异常检查。
f) Builder模式的不足之处:必须先构建Builder对象。所以相比前面两种方式它更消耗性能,必须在有很多参数时才适合使用。
总结:当一个类中有多个参数,在创建该类对象的业务需求中,要求客户端在构建该对象时可以选定要构建的参数时,考虑使用构建器模式