高效Java第一条考虑用静态工厂代替构造函数

获得类的实例:
1.提供一个公有的构造函数;
2.提供一个公有的静态工厂方法,该方法只是一个返回类的实例的静态方法。


静态工厂方法与设计模式中的工厂方法模式不同。

提供静态工厂方法的优势——静态工厂方法与构造函数不同的第一大优势在于,它们有名称

如果构造函数的参数本身没有确切地描述正被返回的对象,那么具有适当名称的静态工厂会更容易被使用,产生的客户端代码也更易于阅读。

BigInteger(int,int,Random)返回的BigInteger可能为素数,如果用名为BigInteger.probablePrime的静态方法来表示,会更为清楚。
一个类只能有一个带有指定签名的构造函数。
提供两个构造函数,它们的参数列表只在参数类型的顺序上有所不同。这不是好主意。用户永远也记不住该用哪个构造函数,因此会经常调用错误的构造函数。并且,读调用这些构造函数的代码是有难度的。

当一个类需要多个带有相同签名的构造函数时,可以用静态工厂方法代替构造函数,通过慎重地选择名称可以突出它们之间的区别。

提供静态工厂方法的优势——静态工厂方法与构造函数不同的第二大优势在于,不必在每次调用它们的时候都创建一个新的对象

可以避免创建不必要的重复对象。
Booelan.valueOf(booelan)方法从不创建对象。
类似于Flyweight模式。
如果程序经常请求创建相同的对象,并且创建对象的代价很好,则这项技术可以极大地提升性能。

实例受控的类:静态工厂方法能够为重复的调用返回相同的对象,这样有助于类总能严格控制在某个时刻那些实例应该存在。

提供静态工厂方法的优势——静态工厂方法与构造函数不同的第三大优势在于,它们可以返回原返回类型的任何子类型的对象

API可以返回对象,又不会使对象的类变成公有的。以这种方式隐藏实现类会使API变得非常简洁。
这项技术适用于基于接口的框架,接口为静态工厂方法提供了自然返回类型。
接口不能有静态方法,因此按照惯例,接口Type的静态工厂方法被放在一个名为Types的不可实例化的类中。

Collections Framework API比导出32个独立公有类的实现方式要小得多,每种便利实现都对应一个类。这不仅是API数量上减少,也是概念意义上的减少。
被返回的对象是由相关的接口精确指定的。
使用这种静态工厂方法时,甚至要求客户端通过接口来引用被返回的对象,而不是通过它的实现类来引用被返回的对象,这是一种良好的习惯。

公有的静态工厂方法所返回的对象的类不仅可以是非公有的,而且该类还可以随着每次调用而发生变化,这取决于静态工厂方法的参数值。只要是已声明的返回类型的子类型,都是允许的。为了提升软件的可维护性和性能,返回对象的类也可能随着发行版本的不同而不同。

JDK5引入的java.util.EnumSet没有公有构造函数,只有静态工厂方法。它返回两种实现类之一,取决于底层枚举类型的大小:如果元素有64个或者更少,静态工厂方法就会返回一个RegularEnumSet实例,用单个long进行支持;如果枚举类型有65个或者更多元素,工厂就返回JumboEnumSet实例,用long数组进行支持。
这两个实现类对客户来说是不可见的。如果RegularEnumSet不能再给小的枚举类型提供性能优势,就可能从未来的发行版本中被删除,这不会造成不良的影响。如果事实证明对性能有好处,在未来的发行版本中可以添加其他的EnumSet实现。客户永远不知道也不关心他们从工厂方法中得到的对象的类,他们只需要知道它是EnumSet的某个子类即可。

静态工厂方法返回的对象所属的类,在编写包含该静态工厂方法的类时可以不必存在。这种灵活的静态工厂方法构成了服务提供者框架的基础(JDBC).

提供静态工厂方法的优势——静态工厂方法与构造函数不同的第四大优势在于,在创建参数化类型实例的时候,它们使代码变得更加简洁。

在调用参数化类的构造函数时,即使类型参数很明显,也必须指明。也就是说要接连两次提供类型参数:

使用静态工厂方法,编译器可以推导出类型参数(类型推导)。

JDK8竟然还会警告。

静态工厂方法的主要缺点在于:类如果不含公有的或者受保护的构造函数,就不能被子类化。

对于公有的静态工厂所返回的非公有类,也是如此。
鼓励程序员使用复合,而不是继承。

静态工厂方法的第二个缺点在于,它们与其他的静态方法没有任何区别。

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

静态工厂方法的惯用名称

valueOf——该方法返回的实例与它的参数具有相同的值。实际上是类型转换方法。
of——valueOf的简洁替代,在EnumSet中使用并流行起来。
getInstance——返回的实例是通过方法的参数来描述的,但是不能够说与参数具有同样的值。对于单例来说,该方法没有参数,并返回唯一的实例。
newInstance——与getInstance一样,但newInstance确保返回的每个实例都与所有其他实例不同。
getType——在工厂方法处于不同的类中的时候使用。Type表示工厂方法所返回的对象类型。
newType——在工厂方法处于不同的类中的时候使用。Type表示工厂方法所返回的对象类型。

服务提供者框架概念

服务提供者框架:多个服务提供者实现一个服务,系统为服务提供者的客户提供多个实现,并把他们从多个实现中解耦出来。

服务提供者三个组件

服务接口:提供者实现
提供者注册API:系统用来注册实现,让客户访问它们
服务访问API:客户端用来获取服务的实例

服务访问API允许但是不要求客户端指定某个选择提供者的条件,如果没有指定,则返回默认的实现。服务访问API是灵活的静态工厂,它构成了服务提供者框架的基础。

服务提供者可选组件

服务提供者接口,这些提供者负责创建其服务实现的实例。如果没有服务提供者接口,实现就按照类名称注册,并通过反射方式进行实例化。

服务提供者例子——JDBC

Connection服务接口
DriverManager.registerDriver是提供者注册API
DriverManager.getConnection是服务访问API
Driver是服务提供者接口

编写实例受控的类的原因

实例受控使得类可以确保它是一个单例或是不可实例化的。
实例受控使得不可变类可以确保不会存在两个相等的实例,即当且仅当a==b的时候才有a.equals(b)true。如果类保证了这一点,它的客户端就可以使用==操作符来代替equals(Object)方法,这样可以提升性能。

总结

静态工厂通常更加适合,因此切忌第一反应就是提供公有的构造函数,而不优先考虑静态工厂。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,544评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,430评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,764评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,193评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,216评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,182评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,063评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,917评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,329评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,543评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,722评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,425评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,019评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,671评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,825评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,729评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,614评论 2 353

推荐阅读更多精彩内容