Java静态工厂方法 —— 有了它,你还需要工厂模式吗

原创 2017年05月28日 10:41:55

本文结合《Effective Java》第二章条目一《考虑用静态工厂方法代替构造器》和自己的理解及实践,讲解了Java静态工厂方法的知识点,并在文末附上了自己对静态工厂方法和工厂模式的区别的理解,文章发布于专栏Effective Java,欢迎读者订阅。


什么是静态工厂方法

对于类而言,为了让使用者获取它自身的一个实例,最常用的方法就是提供一个公有的构造器。

当然,这里要介绍的是另一种方法——静态工厂方法,一个返回类的实例的静态方法。

举个例子,Boolean的一个将基本类型boolean转为封装类的方法,valueOf:

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

为什么要使用静态工厂方法

那么,我们为什么要使用静态工厂方法,而不是使用构造器呢?

因为静态工厂方法,具有以下三个特点——具名、环保、多子,下面一个个来讲。

> 具名  静态工厂方法有名称

对于构造器来说,根据入参的不同可以有多个构造器,但是这些构造器的名称都是一样的,使用者在调用时就会一头雾水,到底应该调用哪一个呢。

而使用了静态工厂方法之后,你可以根据方法的功能给方法起不同的名字,只有名字起得好,使用者看到方法名就知道是什么意思,知道这时候应该调用哪一个方法,大大提高了代码的可读性。

> 环保  不必每次调用的时候都创建一个新对象

使用构造器,每次都会产生一个新的对象。

而静态工厂方法,可以重复地返回预先创建好的对象。

上面Boolean就是一个非常好的例子,TRUE和FALSE两个变量都是预先创建好的,而且都是不可变的final对象,谁需要用到了,就给它返回过去,也不用担心被修改了。

下面就是TRUE和FALSE两个变量的初始化代码:

public final class Boolean implements java.io.Serializable,
                                      Comparable<Boolean>
{
    /**
     * 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);

    ...   
}

> 多子  可以返回原返回类型的任何子类型的对象

使用构造器,你只能返回一种类型的对象;而使用静态工厂方法,你可以根据需要,返回原返回类型的任何子类型的对象

以EnumSet的noneof方法为例:

    /**
     * Creates an empty enum set with the specified element type.
     *
     * @param elementType the class object of the element type for this enum
     *     set
     * @throws NullPointerException if <tt>elementType</tt> is null
     */
    public static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> elementType) {
        Enum[] universe = getUniverse(elementType);
        if (universe == null)
            throw new ClassCastException(elementType + " not an enum");

        if (universe.length <= 64)
            return new RegularEnumSet<>(elementType, universe);
        else
            return new JumboEnumSet<>(elementType, universe);
    }

这个方法,出于性能的考虑,具体返回什么类型,由枚举类型的数量决定,超过64,则返回JumboEnumSet,否则返回RegularEnumSet,而这两种类对于使用者来说是不可见的,使用者只需要知道他是EnumSet就好。


也正是因为静态工厂方法有着比构造器更大的优势,我们在创建类时,切忌第一反应就是提供公有构造器,要优先考虑静态工厂方法。


常见的静态工厂方法

这里附上静态工厂方法的一些约定俗成的名称:

valueOf/Of——类型转换,返回的实例和入参具有相同的值,比如Boolean.valueOf()、EnumSet.valueOf()

getInstance——返回一个预先创建好的实例

newInstance——返回一个新的实例


静态工厂方法难道不就是工厂模式吗?

讲到这里,可能会有很多人觉得这不就是工厂模式吗?答:并不完全相同。

本文讲的静态工厂方法,和工厂模式一样,都是用来取代构造器的方法,都具有上面说的三个优势:具名、环保、多子。

但是,两者的实现方式和使用场景并不相同。

首先,直观上看,在代码结构上,我们说的工厂模式,通常需要一个xxxFactory类,在里面定义工厂方法;而本文讲的静态工厂方法,则只需要一个类,类本身就提供了生产对象的工厂方法。

其次,我们想一下,假如一个类,在设计的时候,就提供了静态工厂方法,那么还需要使用工厂模式吗?

是的,不需要。

也就是说,只有当一个类没有提供静态工厂方法的时候,我们才需要使用工厂模式。

脑洞一下,假如苹果公司有强大的零部件工厂,那它还需要富士康吗?


总结

静态工厂方法具有三大优势——具名、环保、多子。

如果一个类提供了静态工厂方法,那么也就不需要考虑对这个类进行工厂模式了。

我们在创建类时,切忌第一反应就是提供公有构造器,要优先考虑静态工厂方法。






版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

静态工厂模式

静态工厂、参数化工厂(parameterized factory)

java中简单工厂模式(静态工厂方法模式)

简单工厂模式 简单工厂模式也叫做静态工厂方法模式。 简单工厂模式组成: • 工厂类角色:本模式的核心,含有一定的商业逻辑和判断逻辑,是由一个具体类实现。 • 抽象产品角色:具体产品抽象...

NS2脚本中如何使用God(转)

ns2, god

简单工厂模式 VS 工厂方法模式

准备知识 在OO设计领域,我们知道前人总结了不少的经验,许多的经验在现代软件工程过程中已经被认为是原则来遵守。下面笔者摘抄几项下文涉及到的OO原则的定义。 OCP(开闭原则,Open-Clos...

静态工厂方法

静态工厂方法讲解        创建类的实例的最常见的方式是用new语句调用类的构造方法。在这种情况下,程序可以创建类的任意多个实例,每执行一条new语句,都会导致Java虚拟机的堆区中产生一个新的对...

用小说的形式讲解Spring(3) —— xml、注解和Java Config到底选哪个

有时候选择多了,也会带来烦恼

这一次,让我们来好好聊聊Java泛型

本文结合《Effective Java》第五章泛型和自己的理解及实践,讲解了Java泛型的知识点。

JAVA设计模式之工厂模式(简单工厂模式+工厂方法模式)

在面向对象编程中, 最通常的方法是一个new操作符产生一个对象实例,new操作符就是用来构造对象实例的。但是在一些情况下, new操作符直接生成对象会带来一些问题。举例来说, 许多类型对象的创造需要一...

《Spring技术内幕》学习笔记1——IoC容器体系结构

1. BeanFactory类结构体系: BeanFactory接口及其子类定义了Spring IoC容器体系结构,由于BeanFactory体系非常的庞大和复杂,因此要理解Spring IoC,需...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)