单例(singleton)就是一个只实例化一次的类。使类成为单例可能会使它的测试变得困难,因为除非它实现了作为其类型的接口,否则不可能用模拟实现来代替这个单例。下面是几种实现单例的方法:
使用 public field 方法
// Singleton with public final field
public class Elvis {
public static final Elvis INSTANCE = new Elvis();
private Elvis() { ... }
public void leaveTheBuilding() { ... }
}
私有构造器只会被调用一次来初始化用 public static final
修饰的属性 INSTANCE
。因为没有 public
和 protected
的构造器,这里只会存在一个 Elvis 实例。
该方法的优点:
- API 明确表示这个类就是一个单例。公共静态属性是 final 的,所以它总是包含相同的对象引用。
- 这个方法很简单。
使用 static factory 方法
// Singleton with static factory
public class Elvis {
private static final Elvis INSTANCE = new Elvis();
private Elvis() { ... }
public static Elvis getInstance() { return INSTANCE; }
public void leaveTheBuilding() { ... }
}
所有对 Elvis.getInstance
的调用都返回相同的对象引用,并且不会创建其他的Elvis实例。
该方法的优点:
- 可以方便地将类的实现改为非单例,并且用户代码不需要改变。
- 可以编写一个泛型单例工厂。
- 方法引用可以被用作 supplier,例如
Elvis::instance
等同于Supplier<Elvis>
。
使用只有一个元素的枚举类型
// Enum singleton - the preferred approach
public enum Elvis {
INSTANCE;
public void leaveTheBuilding() { ... }
}
这个方法与 public field 方法相似,但是更加简洁。这个方法看起来有一点不自然,但它通常是实现单例的最好方法。
注意:如果单例必须继承 Enum
以外的父类(尽管可以声明一个 Enum
来实现接口),那么就不能使用这种方法。