著名 Java 书籍《Effective Java》中第一条就提到了一个原则: 考虑用静态方法而不是构造器. 初看这条规则的时候我还感到很费解, 构造器是 Java 提供的构造对象的方法, 为什么不是首选呢?
假设有这样一个类:
- package com.example.demo;
- public class Dog {
- private String name;
- private String color;
- private int age;
- public Dog() {
- }
- public Dog(String name) {
- this.name = name;
- }
- public Dog(String name, String color, int age) {
- this.name = name;
- this.color = color;
- this.age = age;
- }
- }
一条狗的属性很多, 比如名字, 颜色和年龄, 我上面的类里有三个构造器, 一个无参数的默认构造器, 一个参数只有 name 的构造器和一个有所有三个参数的构造器.
那么这个时候问题来了, 我想加一个只有毛色 color 参数的构造器, 因为确实有些狗我只知道它的颜色, 但是这已经是不可能了:
- public Dog(String color) {
- this.color = color;
- }
方法重载也是有限制的, 这个构造器实际上和 name 构造器冲突了.
为了实现功能, 我们还是改改代码的好:
- package com.example.demo;
- public class Dog {
- private String name;
- private String color;
- private int age;
- private Dog() {
- }
- public static Dog newDogWithAllParam(String name, String color, int age) {
- Dog dog = new Dog();
- dog.name = name;
- dog.age = age;
- dog.color = color;
- return dog;
- }
- public static Dog newDogWithName(String name) {
- Dog dog = new Dog();
- dog.name = name;
- return dog;
- }
- public static Dog newDogWithColor(String color) {
- Dog dog = new Dog();
- dog.color = color;
- return dog;
- }
- // Getters & Setters
- }
每次新建对象的时候, 只需要调度需要的方法就可以了. 这段代码也解释了书中提到的静态工厂方法的一个好处 -- 有名字. 通过名字我可以清楚的知道我是用什么属性去创建的对象.
我个人很喜欢使用 Guava 的 Lists 类库来创建 List:
List<Long> list = Lists.newArrayList();
这种方式可以说简洁而优雅, 其实, 这也是静态工厂方法取代构造器的典型案例, 它的源码可以来品味一下:
- @GwtCompatible(serializable = true)
- public static <E> ArrayList<E> newArrayList() {
- return new ArrayList<>();
- }
其实和我之前的代码原理上是一样的.
《Effective Java》还提到了一条, 就是静态工厂方法不必在每次被调用的时候都会产生新对象, 照例要看源码, 我们看一下书里提供的一段代码:
- public static Boolean valueOf(boolean b) {
- return b ? Boolean.TRUE : Boolean.FALSE;
- }
在这样的语句: boolean bl = Boolean.valueOf(false); 的时候, 实际上是不需要创建额外的对象的, 原因在我之前写 static 的文章中有提及:
Java 之再看 static 变量
虽然上面的例子基本上是一句废话, 但是也能说明问题.
静态工厂方法还有一个好处, 就是可以返回子类型, 比如我们有一个 Car 类, 其中有一个关键的参数叫做 price, 我希望 price>30 万的返回豪车子类, price<30 万的返回买菜车子类, 那么代码就要这样写了:
- package com.example.demo;
- public class Car {
- private int price;
- Car() {}
- public static Car newCarWithPrice(int price) {
- if (price> 30 * 10000) {
- return new LuxCar();
- } else {
- return new NormalCar();
- }
- }
- }
这种代码就是构造器无法实现的了.
来源: http://www.jianshu.com/p/3f6530e166d9