什么是“静态工厂”方法?
什么是“静态工厂”方法?
Foo x = new Foo()
。使用这种模式,你应该调用工厂方法:Foo x = Foo.create()
。构造函数被标记为私有,因此除了类内部,无法调用它们,而工厂方法被标记为static
,因此可以在没有对象的情况下调用它。null
。Coordinate c = Coordinate.createFromCartesian(double x, double y)
和
Coordinate c = Coordinate.createFromPolar(double distance, double angle)
如 Rasmus 所指出的那样,这也可以用于提高可读性。
注意!“静态工厂方法与工厂方法模式不同” (c) Effective Java, Joshua Bloch。
工厂方法:“定义一个创建对象的接口,但让实现该接口的类来决定实例化哪个类。工厂方法让类推迟实例化到子类中进行” (c) GoF。
“静态工厂方法只是一个返回类实例的静态方法。” (c) Effective Java, Joshua Bloch。通常这个方法在特定的类中。
它们之间的区别:
静态工厂方法的关键思想是获得对对象创建的控制,并将其委托从构造函数转移到静态方法中。创建对象的决策,像在抽象工厂中一样,在方法之外(在常见情况下,但并非总是如此)。而工厂方法的关键(!)思想是将创建类实例的决策委托给工厂方法内部。例如,经典的单例模式就是静态工厂方法的一种特殊情况。常用的静态工厂方法示例如下:
我们避免直接访问数据库连接,因为它们很耗资源。所以我们使用一个静态工厂方法getDbConnection
来创建连接,如果我们低于限制,则创建连接。否则,它会尝试提供“备用”连接,如果没有,则失败并抛出异常。
public class DbConnection{
private static final int MAX_CONNS = 100;
private static int totalConnections = 0;
private static Set<DbConnection> availableConnections = new HashSet<DbConnection>();
private DbConnection(){
// ...
totalConnections++;
}
public static DbConnection getDbConnection(){
if(totalConnections < MAX_CONNS){
return new DbConnection();
}else if(availableConnections.size() > 0){
DbConnection dbc = availableConnections.iterator().next();
availableConnections.remove(dbc);
return dbc;
}else {
throw new NoDbConnections();
}
}
public static void returnDbConnection(DbConnection dbc){
availableConnections.add(dbc);
//...
}
}
通过使用静态工厂方法可以提高可读性:
对比:
public class Foo{
public Foo(boolean withBar){
//...
}
}
//...
// What exactly does this mean?
Foo foo = new Foo(true);
// You have to lookup the documentation to be sure.
// Even if you remember that the boolean has something to do with a Bar
// you might not remember whether it specified withBar or withoutBar.
TOpublic class Foo{
public static Foo createWithBar(){
//...
}
public static Foo createWithoutBar(){
//...
}
}
// ...
// This is much easier to read!
Foo foo = Foo.createWithBar();
private Foo(boolean withBar){/*..*/}
public static Foo createWithBar(){return new Foo(true);}
public static Foo createWithoutBar(){return new Foo(false);}
- Rasmus Faber
- 和构造方法不同,具有名称,可以使代码更加清晰明了。
- 无需在每次调用时创建新对象 - 如果需要,可以缓存并重复使用对象。
- 可以返回其返回类型的子类型 - 特别地,可以返回一个其实现类对调用者未知的对象。这是许多框架中广泛使用的非常有价值的特性,这些框架将接口作为静态工厂方法的返回类型。
所有问题归结为可维护性。最好的方式是,每当使用new
关键字创建对象时,就将编写的代码与实现耦合在一起。
工厂模式让您将对象的创建与对其执行操作分离开来。当您使用构造函数创建所有对象时,实际上是将使用对象的代码与该实现硬连接在一起。使用您的对象的代码"依赖于"该对象。表面上可能看起来不是很重要,但是当对象发生更改(比如更改构造函数的签名或子类化对象)时,必须返回并在各个地方重新连接它们。
今天,工厂在很大程度上已被放弃,转而使用依赖注入,因为它们需要大量的样板代码,这些样板代码很难自行维护。依赖注入基本上相当于工厂,但允许您通过配置或注释声明指定对象如何组合在一起。
class Test{
int x, y;
private Test(){
.......
.......
}
}
public static Test getObject(){
return new Test();
}
现在,您可以从类的外部创建此类的对象。就像这样...
Test t = Test.getObject();
Static Factory Method
相较于公共构造函数有何优势呢? - Shenpublic static final Test Instance = new Test();
您可以通过以下方式获取对象:Test.Instance.getObject();
- SangLe我想为这篇文章增加一些关于我所知道的内容。我们在最近的安卓项目中广泛使用了这种技术。与其使用 "new" 运算符创建对象,你也可以使用静态方法来实例化一个类。代码清单如下:
我认为将这个技巧分享给更多人是非常有益的。
//instantiating a class using constructor
Vinoth vin = new Vinoth();
//instantiating the class using static method
Class Vinoth{
private Vinoth(){
}
// factory method to instantiate the class
public static Vinoth getInstance(){
if(someCondition)
return new Vinoth();
}
}
静态方法支持条件对象创建:每次调用构造函数都会创建一个对象,但你可能并不想要这样。假设你只想在满足某些条件时才创建新对象。除非条件得到满足,否则你并不会每次创建一个新的Vinoth实例。
另一个例子来自于Effective Java。
public static Boolean valueOf(boolean b) {
return (b ? TRUE : FALSE);
}
这种方法将布尔值转换为布尔对象引用。 Boolean.valueOf(boolean)
方法告诉我们,它从不创建对象。静态工厂方法
的能力可以从重复调用中返回同一对象,使得类可以严格控制任何时候存在的实例。
静态工厂方法
不同于 构造函数
的是,它们可以返回其返回类型的任何子类型的 对象
。这种灵活性的一个应用是API可以返回对象而不使它们的类公开。以这种方式隐藏实现类会导致非常紧凑的API。
Calendar.getInstance()
是上述情况的一个很好的例子,它根据语言环境创建一个 BuddhistCalendar
、JapaneseImperialCalendar
或默认的一个 Georgian
。
另一个我想到的例子是Singleton模式
,其中您使构造函数私有化并创建一个自己的 getInstance
方法,在该方法中确保始终只有一个实例可用。
public class Singleton{
//initailzed during class loading
private static final Singleton INSTANCE = new Singleton();
//to prevent creating another instance of Singleton
private Singleton(){}
public static Singleton getSingleton(){
return INSTANCE;
}
}
静态工厂的一个优点是API可以返回对象而不需要使它们的类公开。这导致了非常紧凑的API。在Java中,这是通过Collections类实现的,该类隐藏了大约32个类,从而使集合API非常紧凑。
工厂方法是一种抽象化对象实例化的方法。通常情况下,当您需要一个实现某个接口的类的新实例,但不知道具体实现类时,工厂就非常有用。
在处理相关类层次结构时,工厂方法非常有用,例如GUI工具包。如果您只是简单地硬编码调用每个小部件的具体实现构造函数,但如果您想要将一个工具包替换为另一个,则需要修改很多代码。通过使用工厂,您可以减少需要更改的代码量。