一个类允许客户端获取其实例的传统方式是提供一个公共构造方法。

还有另一种技术,就是:静态工厂方法。一个类可以提供一个公共静态工厂方法,它只是一个返回类实例的静态方法。 比如 Boolean 类中的一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static final Boolean TRUE = new Boolean(true);

public static final Boolean FALSE = new Boolean(false);

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

public static Boolean valueOf(String s) {
return parseBoolean(s) ? TRUE : FALSE;
}

public static boolean parseBoolean(String s) {
return "true".equalsIgnoreCase(s);
}

文档注释中有说明:通常应优先使用此方法而不是构造函数布尔 Boolean,因为此方法可能会产生更好的空间和时间性能。

一、工厂方法的优点

提供静态工厂方法有如下优点:

  • 静态工厂方法是有名字的。一个类只能有一个给定签名的构造方法,可以通过提供两个构造方法来解决这个限制,这两个构造方法的参数列表只有它们的参数类型的顺序不同。 这是一个非常糟糕的主意。 这样的 API 用户将永远不会记得哪个构造方法是哪个,最终会错误地调用。
  • 静态工厂方法不需要每次调用时都创建一个新对象。这允许不可变类使用预先构建的实例,或在构造时缓存实例,并反复分配它们以避免创建不必要的重复对象。
  • 静态工厂方法可以返回其返回类型的任何子类型的对象。这种灵活性可以使 API 可以返回对象而不需要公开它的类。
  • 静态工厂方法返回对象的类可以根据输入参数的不同而不同。比如 EnumSet 的静态工厂方法在根据枚举类型返回 EnumSet 时,会判断枚举类的成员数量是否超过 64,超过 64 返回 JumboEnumSet,小于等于 64 则返回 RegularEnumSet,这两个类都是 EnumSet 的子类。这两个实现类对于客户是不可见的,客户不需要关心工厂方法返回的对象的类别,只关心返回类型是否是 EnumSet 的子类。
  • 在编写包含静态工厂方法的类时,返回的对象的类不需要存在。这种灵活的静态工厂方法构成了服务提供者框架的基础,比如 Java 数据库连接 API。

1、服务提供者框架

服务提供者框架是提供者实现服务的系统,并且系统使得实现对客户端可用,从而将客户端从实现中分离出来。服务提供者框架。

服务提供者框架中有三个基本组:

  • 服务接口,它表示实现
  • 提供者注册 API,提供者用来注册实现
  • 服务访问 API,客户端使用该 API 获取服务的实例

服务访问 API 允许客户指定选择实现的标准。在缺少这样的标准的情况下,API 返回一个默认实现的实例,或者允许客户通过所有可用的实现进行遍历。服务访问 API 是灵活的静态工厂,它构成了服务提供者框架的基础。

服务提供者框架的一个可选的第四个组件是一个服务提供者接口,它描述了一个生成服务接口实例的工厂对象。

服务提供者框架模式有许多变种。例如,服务访问 API 可以向客户端返回比提供者提供的更丰富的服务接口。这是桥接模式。依赖注入框架可以被看作是强大的服务提供者。 从 Java 6 开始,平台包含一个通用的服务提供者框架 java.util.ServiceLoader,所以你不需要,一般也不应该自己编写。

二、工厂方法的缺点

工厂方法有如下缺点:

  • 只提供静态工厂方法的主要限制是:没有公共或受保护构造方法的类不能被子类化。例如 Collections
  • 另一个缺点是:静态工厂方法不像构造方法那样在 API 文档中突出,因此很难找出如何实例化一个提供静态工厂方法而不是构造方法的类。Javadoc 工具可能有一天会引起对静态工厂方法的注意。与此同时,可以通过将注意力吸引到类或接口文档中的静态工厂以及遵守通用的命名约定来减少这个问题。下面是一些静态工厂方法的常用名称:
    • from
    • of,比如 List.of()
    • valueOf
    • instancegetInstance
    • createnewInstance
    • getXXX,XXX 为类名
    • newXXX,XXX 为类名
    • XXX,XXX 为类名

相关链接

OB tags

#Java