什么是“静态工厂”方法?
14 回答
静态工厂方法模式是一种封装对象创建的方法。如果没有工厂方法,您只需直接调用类的构造函数:Foo x = new Foo()
. 使用这种模式,您将改为调用工厂方法: Foo x = Foo.create()
。构造函数被标记为私有,因此只能从类内部调用它们,工厂方法被标记为static
可以在没有对象的情况下调用它。
这种模式有几个优点。一是工厂可以从许多子类(或接口的实现者)中选择并返回。这样,调用者可以通过参数指定所需的行为,而不必知道或理解潜在的复杂类层次结构。
正如 Matthew 和 James 所指出的,另一个优势是控制对有限资源(例如连接)的访问。这是一种实现可重用对象池的方法——而不是构建、使用和拆除对象,如果构建和销毁是昂贵的过程,那么构建一次并回收它们可能更有意义。null
工厂方法可以返回一个现有的、未使用的实例化对象,如果它有一个,或者如果对象计数低于某个下限阈值,则构造一个,或者如果它高于上限阈值,则抛出异常或返回。
根据 Wikipedia 上的文章,多个工厂方法还允许对类似参数类型进行不同的解释。通常构造函数与类具有相同的名称,这意味着您只能拥有一个具有给定签名的构造函数。工厂不受限制,这意味着您可以有两种不同的方法来接受相同的参数类型:
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) 有效的 Java,Joshua Bloch。通常这个方法在一个特定的类中。
区别:
静态工厂方法的关键思想是控制对象的创建并将其从构造函数委托给静态方法。要创建的对象的决定就像在抽象工厂中在方法之外做出的一样(在常见情况下,但并非总是如此)。而工厂方法的关键(!)思想是委托决定在工厂方法中创建什么类的实例。例如,经典的 Singleton 实现是静态工厂方法的一个特例。常用的静态工厂方法示例:
- 的价值
- 获取实例
- 新实例
我们避免提供对数据库连接的直接访问,因为它们是资源密集型的。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.
到
public class Foo{
public static Foo createWithBar(){
//...
}
public static Foo createWithoutBar(){
//...
}
}
// ...
// This is much easier to read!
Foo foo = Foo.createWithBar();
- 有名字,不像构造函数,可以澄清代码。
- 无需在每次调用时创建新对象 - 如有必要,可以缓存和重用对象。
- 可以返回其返回类型的子类型 - 特别是,可以返回调用者不知道其实现类的对象。这是许多使用接口作为静态工厂方法的返回类型的框架中非常有价值且广泛使用的特性。
这一切都归结为可维护性。最好的表达方式是,每当您使用new
关键字创建对象时,您就是将正在编写的代码耦合到实现。
工厂模式允许您将创建对象的方式与使用对象的方式分开。当您使用构造函数创建所有对象时,您实际上是将使用该对象的代码硬连接到该实现。使用您的对象的代码“依赖于”该对象。从表面上看,这似乎没什么大不了的,但是当对象发生更改时(考虑更改构造函数的签名,或对对象进行子类化),您必须返回并在各处重新连接。
今天,工厂在很大程度上被搁置在使用依赖注入的支持下,因为它们需要大量的样板代码,结果证明自己有点难以维护。依赖注入基本上等同于工厂,但允许您指定对象如何以声明方式连接在一起(通过配置或注释)。
如果一个类的构造函数是私有的,那么你不能从它的外部为类创建一个对象。
class Test{
int x, y;
private Test(){
.......
.......
}
}
我们不能从外部为上述类创建对象。所以你不能从课堂外访问 x, y。那么这个类有什么用呢?
这是答案:工厂方法。
在上面的类中添加以下方法
public static Test getObject(){
return new Test();
}
所以现在你可以从它的外部为这个类创建一个对象。就像路...
Test t = Test.getObject();
因此,通过执行其私有构造函数返回类对象的静态方法称为FACTORY方法
。
我想我会在这篇文章中添加一些关于我所知道的内容。我们在我们的recent android project
. 代替creating objects using new operator
你也可以static method
用来实例化一个类。代码清单:
//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)
方法向我们展示了,它从不创建对象。static factory methods
从重复中返回相同对象的能力invocations
允许类在任何时候保持对存在的实例的严格控制。
Static factory methods
是,与 不同constructors
,它们可以返回object
任何subtype
返回类型中的一个。这种灵活性的一个应用是 API 可以返回对象而无需公开它们的类。以这种方式隐藏实现类会导致 API 非常紧凑。
BuddhistCalendar
Calendar.getInstance() 是上面的一个很好的例子,它根据语言环境 aJapaneseImperialCalendar
或默认情况下创建一个Georgian
。
我能想到的另一个例子是Singleton pattern
,你让你的构造函数私有创建一个你自己的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;
}
}
工厂方法是一种抽象出对象实例化的方法。通常,当您知道需要实现某个接口但不知道实现类的类的新实例时,工厂很有用。
这在处理相关类的层次结构时很有用,一个很好的例子就是 GUI 工具包。您可以简单地对构造函数的调用进行硬编码,以实现每个小部件的具体实现,但是如果您想将一个工具包换成另一个工具包,那么您将有很多地方需要更改。通过使用工厂,您可以减少需要更改的代码量。
源自静态工厂的优点之一是 API 可以返回对象而无需公开其类。这导致非常紧凑的 API。在 java 中,这是通过 Collections 类实现的,该类隐藏了大约 32 个类,这使得它的集合 API 非常紧凑。
具有私有构造函数的静态工厂方法的优点之一(必须限制外部类的对象创建以确保不会在外部创建实例)是您可以创建实例控制的类。并且实例控制的类保证在程序运行期间不存在两个相等的不同实例(a.equals(b) 当且仅当 a==b),这意味着您可以使用==运算符而不是equals方法检查对象的相等性,根据有效的java。
静态工厂方法从重复调用返回相同对象的能力允许类在任何时候保持对存在的实例的严格控制。执行此操作的类被称为实例控制的。编写实例控制类有几个原因。实例控制允许一个类保证它是单例(第 3 项)或不可实例化(第 4 项)。此外,它允许不可变类(第 15 条)保证不存在两个相等的实例:a.equals(b) 当且仅当 a==b 时。如果一个类做出了这种保证,那么它的客户端可以使用 == 运算符而不是 equals(Object) 方法,这可能会提高性能。枚举类型(第 30 项)提供了这种保证。
来自 Effective Java,Joshua Bloch(第 1 项,第 6 页)
当您想确保只有一个实例将返回要使用的具体类时,静态工厂方法是很好的选择。
例如,在一个数据库连接类中,您可能希望只有一个类创建数据库连接,这样如果您决定从 Mysql 切换到 Oracle,您只需更改一个类中的逻辑,应用程序的其余部分将使用新连接。
如果你想实现数据库池,那么也可以在不影响应用程序的其余部分的情况下完成。
它保护应用程序的其余部分免受您可能对工厂进行的更改,这就是目的。
它是静态的原因是如果你想跟踪一些有限的资源(套接字连接或文件句柄的数量),那么这个类可以跟踪有多少已经被传递和返回,所以你不会用尽资源有限。
Java 实现包含实用程序类java.util.Arrays和java.util.Collections它们都包含静态工厂方法、它的示例以及如何使用:
Arrays.asList("1","2","3")
Collections.synchronizedList(..), Collections.emptyList(), Collections.unmodifiableList(...)
(只有一些示例,可以检查 javadocs 以获取 mor 方法示例https://docs.oracle.com/javase/8/docs/api/java/util/Collections.html)
java.lang.String类也有这样的静态工厂方法:
String.format(...), String.valueOf(..), String.copyValueOf(...)
静止的
使用关键字“static”声明的成员。
工厂方法
创建和返回新对象的方法。
在爪哇
编程语言与“静态”的含义有关,但与“工厂”的定义无关。