IT@程序员猿媛程序员

Java之静态工厂方法

2019-04-26  本文已影响37人  有财君

著名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();
        }
    }
}

这种代码就是构造器无法实现的了。

上一篇下一篇

猜你喜欢

热点阅读