何时使用构造函数以及何时使用getInstance()方法(静态工厂方法)?
-
何时以及如何使用构造函数
Foo bar = new Foo();
-
何时以及如何使用getInstance()(静态工厂方法)
Foo bar = Foo.getInstance();
这两者有什么区别,我总是用第一种方式,但是什么时候用第二种方式呢?
每个人似乎都专注于单身人士,而我认为这个问题实际上是关于构造函数与静态工厂方法 。
这实际上是项目1:考虑静态工厂方法,而不是 有效Java 的构造函数 Joshua Bloch:
项目1:考虑静态工厂方法,而不是构造函数
一个类允许客户端获取自己的实例的正常方式是提供一个公共构造函数。 还有另一种技术应该成为每个程序员工具箱的一部分。 一个类可以提供一个公共静态工厂方法 ,它只是一个返回类实例的静态方法。 下面是一个简单的例子(
Boolean
原始types的盒装原语类)。 此方法将布尔原始值转换为Boolean
对象引用:public static Boolean valueOf(boolean b) { return b ? Boolean.TRUE : Boolean.FALSE; }
请注意,静态工厂方法与“ devise模式 ”中的“ 工厂方法” 模式不同 [Gamma95, 107]。 在这个项目中描述的静态工厂方法在devise模式中没有直接的等价物。
一个类可以为其客户端提供静态工厂方法,而不是或者除了构造函数之外。 提供静态工厂方法而不是公共构造函数有两个优点和缺点。
优点(引用这本书):
- 静态工厂方法的一个优点是,不像构造函数,它们有名字。
- 静态工厂方法的第二个优点是,不像构造函数,每次调用时都不需要创build一个新的对象。
- 静态工厂方法的第三个优点是,与构造函数不同,它们可以返回其返回types的任何子types的对象。
- 静态工厂方法的第四个优点是它们减less了创build参数化types实例的冗长性。
缺点(仍然引用这本书):
- 仅提供静态工厂方法的主要缺点是没有公共或受保护的构造函数的类不能被子类化。
- 静态工厂方法的第二个缺点是它们不容易与其他静态方法区分开来。
你有两个问题:什么时候应该调用 getInstance()
方法,什么时候应该创build一个?
如果您决定是否调用 getInstance()
方法,那很简单。 你只需要阅读类文件来找出什么时候应该调用它。 例如, NumberFormat
提供了一个构造函数和一个getInstance()
方法; getInstance()
方法会给你一个本地化的NumberFormat
。 另一方面,对于Calendar
,构造函数是受保护的。 你必须调用getInstance()
来获得一个。
如果你决定是否创build一个getInstance()
方法,你需要决定你想要完成什么。 要么你不想让人们调用你的构造函数(你正在创build一个单例或一个工厂 ),或者你不介意(如上面的NumberFormat
,为了方便调用者初始化一些对象)。
长话短说? 不要担心在自己的代码中创buildgetInstance()
方法。 如果时间到了,他们会有用的,你会知道的。 一般来说,如果可以调用类的构造函数,那么即使类提供了getInstance()
方法,也可能会这样做。
getInstance方法的用法:
- 如果你想控制/限制施工,例如Singleton
- 实现工厂模式,例如DriverManager.getConnection
- 当你想提供更好的名称来说明如何构造实例(构造函数必须与类名称相同)时,请检查NumberFormat工厂方法getCurrencyInstance , getIntegerInstance和其他示例。
但大多数时候你的对象将是一个简单的POJO,而使用公共构造函数是最实际和最明显的解决scheme。
U1:来自另一个类的getInstance
要返回不同类的实例:
public class FooFactory { public static Foo getInstance() { return new Foo(); } }
NumberFormat.getInstance
方法可以做到这一点,因为它们实际上会返回DecimalFormat
实例。
U2:单身问题
单例模式限制了面向对象编程的许多好处。 单身人士通常有私人的构造函数,所以你不能扩展它们。 由于您将通过getInstance方法访问它,而不是引用任何接口,所以您将无法将其交换出来用于其他实现。
如果你可以使用它们,那么听起来就像是一个单独执行的单例模式 。
如果您打算在系统中只有一个类的单个实例,并使构造函数保持私有状态,请使用第二个选项。
使用第一个允许build立类的几个对象。
但是不要给你的class级两种可能性。
注意不要过度使用单身人士,只有在系统中只有一个实例存在的情况下才使用它,否则会限制在其他项目中重用class级的可能性。 能够从项目中的任何地方调用getInstance听起来很有意思,但是这使得不清楚谁实际拥有该实例:没有人和/或全部。 如果你在一个项目中有很多单身人士,你可以打赌这个系统devise得不好(通常)。 单身人士应该小心使用,同样的build议比全局variables适用。
一个我总是比较喜欢静态工厂而不是常规构造函数的例子是当我知道对象构造将会很慢的时候。 我在构造函数上做了简单的初始化,但是如果我需要创build一些沉重的东西,我将使用静态方法并logging行为。
单身是邪恶的。 我所看到的问题不在于系统的重复使用和扩展性(尽pipe我可以看到这种情况会如何发生),更重要的是,我无法计算出我看到一个模糊的错误的次数来自单身人士的系统。
如果您确实需要使用单例,请确保它的范围非常窄,即明智地限制系统中知道它的其他对象的数量。