什么是静态工厂方法?

什么是“静态工厂”方法?

226580 次浏览

工厂方法:将对象的实例化抽象出来的方法。一般来说,当你知道你需要一个实现接口的类的新实例,但你不知道实现类时,工厂是有用的。

这在处理相关类的层次结构时非常有用,GUI工具包就是一个很好的例子。您可以简单地对每个小部件的具体实现的构造函数进行硬编码调用,但是如果您想要将一个工具包交换为另一个工具包,那么您将有很多地方需要更改。通过使用工厂,您可以减少需要更改的代码数量。

  • 与构造函数不同,具有名称,可以阐明代码。
  • 不需要在每次调用时创建一个新对象-对象
  • 可以返回其返回类型的子类型-特别是can 返回调用方不知道其实现类的对象。 这是许多框架中非常有价值和广泛使用的特性 使用接口作为静态工厂方法的返回类型。

fromhttp://www.javapractices.com/topic/TopicAction.do?Id=21

我们避免提供对数据库连接的直接访问,因为它们是资源密集型的。因此,我们使用静态工厂方法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);
//...
}
}

这一切都归结为可维护性。最好的方式是无论何时使用new关键字创建对象,都是在将所编写的代码耦合到实现中。

工厂模式允许您将创建对象的方式与使用对象的操作分开。当您使用构造函数创建所有对象时,实际上是将使用该对象的代码硬连接到该实现。使用对象的代码“依赖于”该对象。从表面上看,这似乎不是什么大问题,但当对象发生变化时(比如改变构造函数的签名,或继承对象的子类),您必须返回并在所有地方重新布线。

如今,由于依赖注入需要大量的样板代码,而这些代码本身维护起来有点困难,工厂在很大程度上被忽略了。依赖注入基本上等同于工厂,但允许你以声明的方式(通过配置或注释)指定你的对象如何连接在一起。

当您希望确保只有一个实例将返回要使用的具体类时,静态工厂方法很好。

例如,在一个数据库连接类中,您可能希望只有一个类创建数据库连接,因此如果您决定从Mysql切换到Oracle,您只需更改一个类中的逻辑,而应用程序的其余部分将使用新的连接。

如果您希望实现数据库池,那么也可以在不影响应用程序其余部分的情况下完成。

它保护应用程序的其余部分不受您可能对工厂所做的更改的影响,这就是目的。

它是静态的原因是,如果你想跟踪一些有限的资源(套接字连接或文件句柄的数量),那么这个类可以跟踪已经传递和返回了多少,这样你就不会耗尽有限的资源。

可读性可以通过静态工厂方法来提高:

比较

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();

静态工厂方法模式是一种封装对象创建的方法。如果没有工厂方法,你只需直接调用类的构造函数: Foo x = new Foo()。使用这种模式,你可以调用工厂方法:Foo x = Foo.create()。构造函数被标记为private,因此只能从类内部调用它们,而工厂方法被标记为static,以便可以在没有对象的情况下调用它。

这种模式有几个优点。一个是工厂可以从许多子类(或接口的实现者)中选择并返回。通过这种方式,调用者可以通过参数指定所需的行为,而不必知道或理解潜在的复杂类层次结构。

正如Matthew和James指出的那样,另一个优点是控制对有限资源(如连接)的访问。这是实现可重用对象池的一种方式——而不是构建、使用和拆除一个对象,如果构建和销毁是昂贵的过程,那么构建一次并回收它们可能更有意义。factory方法可以返回一个存在的、未使用的实例化对象(如果它有一个对象),或者在对象计数低于某个较低的阈值时构造一个对象,或者在对象计数高于较高阈值时抛出异常或返回null

根据维基百科上的文章,多个工厂方法还允许对相似的参数类型进行不同的解释。通常构造函数与类具有相同的名称,这意味着对于给定的签名只能有一个构造函数。工厂没有那么多限制,这意味着你可以有两个不同的方法接受相同的参数类型:

Coordinate c = Coordinate.createFromCartesian(double x, double y)

而且

Coordinate c = Coordinate.createFromPolar(double distance, double angle)

Rasmus指出,这也可以用来提高可读性。

注意!“静态工厂方法工厂方法模式相同”(c) Effective Java, Joshua Bloch。

工厂方法:定义一个用于创建对象的接口,但是让实现该接口的类来决定实例化哪个类。Factory方法允许类延迟实例化到子类“(c) GoF”。

静态工厂方法只是一个返回类实例的静态方法。(c)有效的Java,约书亚·布洛赫。通常这个方法在一个特定的类中。

的区别:

静态工厂方法的关键思想是获得对象创建的控制权,并将其从构造函数委托给静态方法。要创建的对象的决定就像在抽象工厂中在方法之外做出的一样(在常见情况下,但不总是如此)。而工厂方法的关键思想是委托决定在工厂方法中创建什么样的类实例。例如,经典的单例实现是静态工厂方法的特殊情况。常用的静态工厂方法示例:

  • 返回对象的值
  • getInstance
  • newInstance

如果类的构造函数是私有的,那么就不能从类的外部为类创建对象。

class Test{
int x, y;
private Test(){
.......
.......
}
}

不能从上面的类的外部创建一个对象。所以你不能从类外访问x y。那么这门课有什么用呢?
下面是答案:工厂方法 在上面的类

中添加下面的方法
public static Test getObject(){
return new Test();
}

现在你可以在这个类的外部创建一个对象。就像……

Test t = Test.getObject();

因此,通过执行类的私有构造函数返回类对象的静态方法被称为工厂方法

我想我会在这篇文章中添加一些我所知道的东西。我们在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实例。

另一个来自有效的Java的例子。

public static Boolean valueOf(boolean b) {
return (b ? TRUE : FALSE);
}

此方法将布尔原语值转换为布尔对象引用。Boolean.valueOf(boolean)方法说明了我们,它从不创建对象。static factory methods从重复的invocations返回相同对象的能力允许类在任何时候对存在的实例保持严格的控制。

Static factory methodsconstructors不同,它们可以返回其返回类型的任意subtypeobject。这种灵活性的一个应用是API可以返回对象,而不需要将它们的类设为公共。以这种方式隐藏实现类可以得到一个非常紧凑的API。

Calendar.getInstance()是一个很好的例子,它根据地区创建BuddhistCalendarJapaneseImperialCalendar或默认的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;
}
}

静态

用关键字'static'声明的成员。

工厂方法

方法,用于创建和返回新对象。

在Java中

编程语言与“静态”的含义相关,但与“工厂”的定义无关。

Java实现包含实用程序类java.util.Arraysjava.util.Collections,它们都包含静态工厂方法,它的例子和如何使用:

还有类有这样的静态工厂方法:

  • String.format(...), String.valueOf(..), String.copyValueOf(...)

静态工厂的优点之一是API可以返回对象,而不需要将它们的类设为public。这导致了非常紧凑的API。在java中,这是通过Collections类实现的,它隐藏了大约32个类,这使得它的集合API非常紧凑。

带有私有构造函数的静态工厂方法的优点之一(必须限制外部类的对象创建,以确保不会在外部创建实例)是您可以创建instance-controlled类。根据Effective java,实例控制类保证在程序运行期间不存在两个相等的不同实例(当且仅当a==b时,a等于(b)),这意味着你可以用= =操作符而不是=方法检查对象的相等性。

静态工厂方法返回相同对象的能力 重复调用允许类对 任何时候存在哪些实例。这样做的类被称为 instance-controlled。写作有几个原因 instance-controlled类。实例控制允许类 保证它是单例(第3项)或不可实例化(第4项)。 同时,它允许一个不可变类(Item 15)做出保证 当且仅当a==b时,不存在两个相等实例:a. = (b)。如果 类做出此保证后,其客户端就可以使用==操作符 而不是equals(Object)方法,这可能会导致改进 的性能。Enum类型(Item 30)提供了这种保证

摘自Effective Java, Joshua Bloch(第1项,第6页)