比较 Java 静态工厂方法与构造函数

1 什么是静态工厂方法

Java 静态工厂方法是在方法前加上 public static,让这个方法变为公开、静态的方法。该方法返回该类的一个实例,就好像一个工厂生产出一个产品。所以称之为静态工厂方法。在 Boolean.java 中有一个静态工厂方法示例:

public static Boolean valueOf(boolean b) {
        return (b ? TRUE : FALSE);
    }
复制代码

这里返回了一个 Boolean 实例。

2 比较静态工厂方法与构造函数

2.1 名称

静态工厂方法可以根据返回实例的性质,定义出具有自描述性质的方法名称。比如 BigInteger 类定义了一个静态工厂方法 probablePrime,用于返回一个 BigInteger 类型的素数:

public static BigInteger probablePrime(int bitLength, Random rnd) {
        if (bitLength < 2)
            throw new ArithmeticException("bitLength < 2");

        return (bitLength < SMALL_PRIME_THRESHOLD ?
                smallPrime(bitLength, DEFAULT_PRIME_CERTAINTY, rnd) :
                largePrime(bitLength, DEFAULT_PRIME_CERTAINTY, rnd));
    }
复制代码

但如果是构造函数,那么只能是类名,比如上例中的 BigInteger。这样就无法从名称上判断返回的 BigInteger 实例到底有什么性质。

2.2 缓存

每次调用构造函数都会创建新的对象。如果需要事先创建好对象,并缓存起来,以供后期复用。那么构造函数方式就不能满足该需求。而静态工厂方法就可以实现。比如 Boolean.java 中的 valueOf 方法,实际上返回的是实现创建好的静态属性 TRUE 与 FALSE:

public static Boolean valueOf(boolean b) {
        return (b ? TRUE : FALSE);
    }
复制代码

下面是事先静态初始化好的TRUE 与 FALSE:

/**
     * The {@code Boolean} object corresponding to the primitive
     * value {@code true}.
     */
    public static final Boolean TRUE = new Boolean(true);

    /**
     * The {@code Boolean} object corresponding to the primitive
     * value {@code false}.
     */
    public static final Boolean FALSE = new Boolean(false);
复制代码

2.3 子类

拥有构造函数的类,可以被子类所继承。但只有静态工厂方法的类却不行。可以使用类组合方式来解决这一问题。

2.4 总结

比较 静态工厂方法 构造函数
名称 可根据情况自定义名称 只能是类名
缓存 可调用重复对象 每次调用都创建新的对象
子类 不能被子类继承 可以被子类继承

3 静态工厂方法命名方式

关键词 说明 入参个数 示例
from 类型转换,A 类型转换为 B 类型。 1 public static Date from(Instant instant)
of 聚合,做合并。 n public static <E extends Enum> EnumSet of(E e1, E e2, E e3)
instance 返回实例,可能是新建的,也可能是复用已创建的实例。 n public static Object instance(int length)
create 返回新建的实例。 n public static Object create(int length)
type 工厂方法不在要返回的类实例中,type 是要返回的类名称。 n public static ArrayList list(Enumeration e)

最后一个示例,方法定义在 Collections 中,要返回的是 ArrayList 实例,所以被命名为 list。

public static <T> ArrayList<T> list(Enumeration<T> e) {
        ArrayList<T> l = new ArrayList<>();
        while (e.hasMoreElements())
            l.add(e.nextElement());
        return l;
    }
复制代码

建议优先考虑使用静态工厂方法来实例化类。


JoshuaBloch. Effective Java中文版.3版[M]. 机械工业出版社, 2018.p.4-8.

Guess you like

Origin juejin.im/post/7074518912406126606