statement:本篇内容只是建立在我目前经验的基础之上,必然有不完善甚至是不正确的地方,请谨慎阅读,如果能指出错误与不足之处,更是不甚感激
一、什么是静态工厂
public class StaticFactoryTest {
public static StaticFactoryTest newInstance() {
return new StaticFactoryTest();
}
}
静态工厂就是利用静态方法来返回一个类的实例
二、静态工厂优点
- 相比于构造器,静态工厂可以有自定义的名字,你再也不用根据参数的数量去判断一个构造器究竟会返回怎样的实例
- 相比于构造器,静态工厂不仅仅只是可以创造一个新的实例,对于可复用的实例,你可以在静态工厂中让其一直只返回一个原始实例
public class StaticFactoryTest {
private static final StaticFactoryTest instance= new StaticFactoryTest();
public static StaticFactoryTest getInstance() {
return instance;
}
}
- 相比于构造器,静态工厂不仅仅只能返回本类的实例,它能返回本类及其子类的实例
public class StaticFactoryTest {
public static StaticFactoryTest newStaticFactoryTestSon() {
return new StaticFactoryTestSon();
}
}
class StaticFactoryTestSon extends StaticFactoryTest{
}
- 使用类型推导,使得静态工厂具有简化创建泛型实例代码的能力
public class StaticFactoryTest<K> {
public static void main(String[] args) {
StaticFactoryTest<Object> test1 = new StaticFactoryTest<Object>();//1
StaticFactoryTest<Object> test2 = StaticFactoryTest.newInstance();//2
}
public static <K> StaticFactoryTest<K> newInstance() {
return new StaticFactoryTest<K>();
}
}
代码1中使用构造器构造实例,两边均要加上<Object>,而代码2中则不用
三、静态工厂该如何正确使用
- 一般来说,提供了静态工厂,则会同时把构造器设定为private,以防止使用者不使用设定的静态工厂去实例化类,但是这样也会带来一个问题,那就是这个类的子类没办法实例化。
- 静态工厂归根结底是一个方法,与其他方法的区分是一个问题,所以静态工厂需要一些规范的命名:
- newInstance --> 表示该工厂创建一个新的实例
- getInstance --> 表示该工厂会根据条件(参数)返回一个符合的实例,不保证是新的
- valueOf --> 表示该工厂将参数转换为对应于本类需求的一个实例,简单来说就是类型转换
- 静态工厂最大的应用就在于实现单例模式
public class StaticFactoryTest {
private static final StaticFactoryTest instance= new StaticFactoryTest();
private StaticFactoryTest() {}
public static StaticFactoryTest getInstance() {
return instance;
}
}
- 静态工厂由于其对构造器进行了一种封装,所以能避免很多潜在的问题,比如this引用溢出的问题
public class StaticFactoryTest implements Runnable{
private final Thread t;
private StaticFactoryTest() {
t = new Thread(this);
t.start();
}
@Override
public void run() {
}
}
上述代码发生了this引用溢出的问题,在构造器中把this赋给一个Thread对象,并且在构造器中开启了线程,要知道构造器中的this对象还是一个未完成的对象,提前发布给一个线程,可能会使得那个线程从这个未完成的对象中得到一些未初始化的东西,从而引发潜在的问题。
public class StaticFactoryTest implements Runnable{
private final Thread t;
private StaticFactoryTest() {
t = new Thread(this);
}
public static StaticFactoryTest newInstance() {
StaticFactoryTest instance = new StaticFactoryTest();
instance.t.start();
return instance;
}
@Override
public void run() {
}
}
上述代码使用静态工厂完美的解决了这个问题,它在对象构造完成之后才启动一个新的线程并返回实例
参考文档:
[1] 《Effective Java》
[2] 《Java concurrency in practice》
网友评论