李福春 · 2020年01月09日

ej3-1优先使用静态工厂方法而非构造函数来创建对象

背景

很早之前就已经自己翻译了,先简单的贴出来,并做一下回顾。

条款1 优先使用静态工厂方法而非构造函数来创建对象

允许客户端创建一个实例的传统方法是:提供一个公共构造函数;有另外一个必须成为每个程序员的编程技巧:优先使用类提供的只简单返回实例的公共静态工厂方法来创建对象。这有一个简单的Boolean类的例子:这个方法转换一个原生的boolean类型的值为一个Boolean的实例。
public static Boolean valueOf(boolean b){
        return b?Boolean.TRUE:Boolean.FALSE;
  }
注意这一点:类的静态工厂方法不同于设计模式的工厂设计模式。本条规约跟设计模式没有关联。
一个类可以通过静态工厂方法也可以使用公共构造函数提供给自己的客户端调用来创建实例,使用静态工厂方法而不是公共构造函数有优点也有缺点。

优点1:它有名字,可读性更好;

构造函数的参数跟自己无关,没有描述返回对象;而良好命名的静态工厂方法客户端代码可读性更好,所以更容易使用;
//使用构造方法,返回一个BigInteger随机素数;
BigInteger(int , int , Random)
//更好的表达方式  
public static BigInteger probablePrime();
一个类构造函数的签名格式是唯一的,程序员围绕这个限制提供了两个构造函数,他们区分的标准是不一样参数的类型组成的参数列表,这真的是一个糟糕的设计,使用这种API的人从来就没办法记住哪个构造函数对应哪个功能,并且容易误用导致调用错误;使用这些构造函数的人只能阅读代码,类文档没法区分。

因为静态工厂方法有名字,所以不存在区分的限制,在一个类有多个签名的构造函数的场景中,应该使用静态工厂方法替代构造函数,并且小心选择名字来区别;

优点2:不需要每次被调用的时候都创建一个新的对象;

这允许构造完毕的不可变类使用提前构建或者缓存的实例,避免创建不必要的重复的对象(分配重复的实例); Boolean.valueOf(boolean) 方法展示了这个技巧,它从来不创建对象,这个技巧类似于享元模式;如果创建代价昂贵的对象被频繁获取,它可以显著的提高性能;这个能力可以让类在任何时刻严格控制实例,这样的类叫做实例可控类,有几个理由应该编写实例可控类:
  1. 实例可控使类需要保证它是单例的实例数量可控;
  2. 需要保证没有两个相同的实例存在;如果a.equls(b) ; 有且只有a == b. 这是基本的享元模式。枚举类型提供了这个保证;

优点3:可以返回子类型,面向抽象编程或者说是接口编程,更灵活;

一个灵活的应用API可以返回非公开的对象,隐藏实现类从而形成契约API,这个技巧使得它可以成为基于接口的框架,接口提供自然的返回类型,(在java8之前,接口没有静态的方法,按照惯例,接口Type静态工厂方法被放到了一个不可实例化的指南类Types中;)

举个例子:java的Collections接口框架有45个种不同的应用实现,提供不可修改集合,同步集合等,几乎所有的这些实现通过一个不可实例化的类Collections的静态工厂方法来对外暴露;所有的返回对象都是非公开的的(即实际返回的是接口实现类或者返回类的子类)。这个集合框架的API比定义45个分开独立的公共类规模要小很多(它减少了集合类的数量负担,也减少了程序员必须掌握使用的API的类数量),程序员知道返回的对象精确的指出了它的接口,所以没有必要去阅读更多的实现类的文档。更进一步,使用这样一个静态工厂方法的客户端只需要参照接口而不用考虑实现类去使用,这是一个最佳实践。

在java8中,接口已经可以添加静态方法了,所以接口可以提供一个不可实例的有常规名字的指南类;接口的很多的公共静态成员放应该替代成接口本身。然而,仍然有必要把这样一个静态工厂方法实现代码放到分开的private 包下的类中;这是因为java8要求接口的静态成员必须是public,java9允许私有的静态方法,但是静态成员和静态内部类任然需要是public的;

原创不易,转载请注明出处。
推荐阅读
关注数
0
文章数
53
爱技术,爱编码,爱生活!
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息