- Consider static factory method instead of constructors
- 考虑使用静态工厂模式替代构造函数
要点回顾
- 静态工厂模式优点
- 可指定具有特定含义的函数名
- 被调用时无需每次都new新的对象
- 可构造子类对象
- 构造对象对外封闭
- 构建静态工厂函数中可以不构造返回的实例
- 静态工厂模式缺点
- 只提供静态工厂方法的类无法被继承
- 静态工厂方法不显而易见
笔记细节
1.1 可指定具有特定含义的函数名
考虑到某个class会有多个构造函数,他们带有不同数量,不同类型的参数。在使用当中,我们很容易混淆这些构造函数及参数的含义。改为使用静态工厂模式构建实例,可通过恰当的函数名来构建易于区分的不同种实例。
例如:
public class Machine {
private boolean on;
private boolean charged;
public Machine(boolean on, boolean charged) {
this.on = on;
this.charged = charged;
}
public Machine(boolean on) {
this.on = on
this.charged = false
}
public static Machine newChargedMachine(boolean on) {
return new Machine(on, true);
}
public static Machine newUnchargedMachine(boolean on) {
return new Machine(on);
}
}
当使用构造函数构建实例时
Machine m = new Machine(false, true);
很难辨认出第一个与第二个参数的具体含义。
当我们引入静态工厂模式
Machine m = Machine.newChargedMachine(true);
很容易通过调用的方法名来区分出构造的实例
1.2 被调用时无需每次都new新的对象
当我们希望重复利用已构建的实例,避免重复构建实例时,我们可以使用singleton模式。例如最简单的singleton模式:
public class Singleton {
public static final Singleton singleton = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return singleton;
}
}
1.3 可构造子类对象
通过静态工厂模式在父类中构造子类对象
public class Animal {
public static Animal newDog() {
return new Dog();
}
public static Animal newCat() {
return new Cat();
}
}
public class Dog extends Animal {}
public class Cat extends Animal {}
1.4 构造对象对外封闭
静态工厂模式可在对外封闭的情况构建新的或者修改现有的子类对象,使用者无需过多了解具体类及实现。java.util.Collections
充分体现了这一点。当我们需要构造一个恒定为空的List时,我们只需调用Collections
内的一个静态方法而无需去了解EmptyList
是怎样的一个子类
List emptyList = Collections.emptyList()
1.5 构建静态工厂函数中可以不构造返回的实例
在静态工厂中,我们甚至可以只表明返回接口的函数,不构造需要返回的实例。而是在运行时动态的载入实例并返回。
public static MyInterface getMyInterfaceInstance() {
//load instance dynamically and return it.
}
参考stackoverflow:https://stackoverflow.com/questions/53240626/what-does-static-factories-returned-object-need-not-exist-mean
2.1 只提供静态工厂方法的类无法被继承
如果只提供静态工厂方法构造实例而没有public或者protected的构造函数,该类将无法被继承。这是一个有争议的缺点因为虽然继承可以复用大量代码,使结构更为清晰化。冗杂与不恰当的继承有时反而会造成代码的过度包装与复杂化。
2.2 静态工厂方法不显而易见
在文档中,静态工厂方法没有构造函数那样显而易见,它没有固定的命名格式。有时,你需要仔细阅读文档才能发现某种静态工厂方法。为了弥补这个缺点,多使用一些惯用的命名规则:
- from - 类型之间的转化,往往只有一个参数
- of - 用于构造某种类型的组合,由多个相同类型参数组成
- valueOf - from的另一种写法
- instance/getInstance - 返回一个实例,若带有参数,参数常表明实例的某些特征选项
- create/newInstance - 与 instance/getInstance 类似,但保证new出一个新的实例
-
getType - 类似 instance/getInstance,但往往会构造另一个类的实例,例如
Files.getFileStore(path);
-
newType - 类似 create/newInstance,但往往会构造另一个类的实例,例如
BufferedReader br = Files.newBufferedReader(path);
- type - 类似 getType 和 newType