《Effective Java》第1条:用静态工厂方法代替构造器

114 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 7 天,点击查看活动详情

今天看讲DDD的领域服务的相关文章中优化代码这一块就讲到了使用静态工厂方法代替构造器。就想到《Effective Java》第一条就是讲这个的,真是知识都是相互关联的呀,晚上特地再翻出来看了一遍,记录一下。

优势

1、静态工厂方法它们有名称

举个例子,使用构造器的new BigInteger(intm int, Random)返回的BigInteger可能为素数,如果用BigInteger.probablePrime的静态工厂方法来表示,显然更清晰。有自己的名称,显然能突出区别、更清晰易懂,从而避免出错。

2、不必在每次调用它们的时候都创建一个新对象

如果返回的是不可变类,可以使用预先构建好的实例,或者将构建好的实例缓存起来,进行重复利用,从而避免创建不必要的重复对象。

3、它们可以返回类型的任何子类型的对象

这样我们在选择返回对象的类型时就有了更大的灵活性。

4、返回的对象的类可以随着每次调用而发生变化,这取决于静态工厂方法的参数值

只要是已声明的返回类型的子类型,都是允许的。返回对象的类也可能随着发行版本的不同而不同。

5、方法返回的对象所属的类,在编写包含该静态工厂方法的类时可以不存在

这种灵活的静态工厂方法构成了服务提供者框架的基础。例如JDBC API。什么是服务提供者框架呢?是指这样一个系统:多个服务提供者实现一个服务,系统为服务提供者的客户端提供多个实现,并把它们从多个实现中解耦出来。

缺点

1、类如果不含公有的或者受保护的构造器,就不能被子类化

例如,想要将Collections Framework中的任何舍不得的实现类子类化,这是不可能的。

2、程序员很难发现它们

在API文档中,它们没有像构造器那样在API文档中明确标识出来,因此对于提供了静态工厂方法而不是构造器的类来说,要想查明如何实例化一个类是非常困难的。

常见的惯用名称

1、from

Date d = Date.from(instant);

2、of

Set<Rank> faceCards = EnumSet.of(JACK, QUEEN, KING);

3、valueOf

BigInteger prime = BigInteger.valueOf(Integer.MAX_VALUE);

4、instance

StackWalker luke = StackWalker.getInstance(options);

5、create或newInstance

Object newArray = Array.newInstance(classObject, arrayLen);

6、getType

FileStore fs = Files.getFilestore(path);

7、newType

BufferedReader br = Files.newBufferedReader(path);

8、type

List<Complaint> litany = Collections.list(legacyLitany);

总结

静态工厂方法和公有构造器都各有用处,我们需要理解它们各自的长处。静态工厂经常更加合适,因此切忌第一反应就是提供仅有的构造器,而不考虑静态工厂。