什么是静态工厂方法?

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

我们避免直接访问数据库连接,因为它们是资源密集型的。 所以我们使用一个静态工厂方法getDbConnection来创build一个连接,如果我们低于极限。 否则,它会尝试提供一个“备用”连接,如果没有连接,则会发生exception。

 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); //... } } 

静态工厂方法模式是封装对象创build的一种方式。 没有工厂方法,你可以直接调用这个类的构造函数 : Foo x = new Foo() 。 有了这个模式,你可以调用工厂方法: Foo x = Foo.create() 。 构造函数被标记为私有的,所以除了在类内部之外,它们不能被调用,并且工厂方法被标记为static以便可以在没有对象的情况下被调用。

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

正如马修和詹姆斯指出的那样,另一个优势是控制对有限资源(如连接)的访问。 这是实现可重用对象池的一种方式,而不是构build,使用和拆除一个对象,如果构build和销毁是昂贵的过程,那么构build它们一次并回收它们可能更有意义。 工厂方法可以返回一个现有的,未使用的实例化对象(如果有的话),或者如果对象计数低于某个下限阈值,则构造一个实例化对象,或者抛出exception,或者如果超出上限阈值,则返回null

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

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

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

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

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

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

“静态工厂方法只是一个返回类的实例的静态方法”。 (c)有效的Java,Joshua Bloch。 通常这个方法是在一个特定的类中。

偏差:

静态工厂方法的关键思想是获取对象创build的控制权并将其从构造函数委派给静态方法。 被创build的对象的决定就像在抽象工厂中做的一样(在一般情况下,而不是总是)。 而Factory Method的关键(!)思想是在Factory Method中委托创build什么类的实例的决定。 例如经典的Singleton实现是静态工厂方法的特例。 常用的静态工厂方法示例:

  • 的价值
  • 的getInstance
  • 的newInstance

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

比较

 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(); 
  • 有名字,不像构造函数,它可以澄清代码。
  • 在每次调用时都不需要创build一个新的对象 – 如果需要的话,可以caching和重用对象。
  • 可以返回它们的返回types的子types – 特别是可以返回一个实现类未知的对象给调用者。 在许多使用接口作为静态工厂方法的返回types的框架中,这是一个非常有价值和广泛使用的特性。

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

这一切归结为可维护性。 最好的方法是每当你使用new关键字创build一个对象的时候,你把你正在编写的代码连接到一个实现。

工厂模式可以让你分离你如何创build一个对象与你所做的对象。 在使用构造函数创build所有对象时,实质上是将使用该对象的代码硬编码到该实现。 使用你的对象的代码是“依赖于”该对象。 这在表面上看起来可能不是什么大不了的事情,但是当对象发生变化时(考虑改变构造函数的签名或者inheritance对象的子类),你必须回头重新布线。

今天的工厂已经被抛在了一边,而不喜欢使用dependency injection,因为它们需要大量的代码,而这些代码实际上难以维护。 dependency injection基本上等同于工厂,但允许你指定你的对象是如何通过configuration或注释声明性地连接在一起的。

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

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

我们不能从外面为上面的课程创build一个对象。 所以你不能从课外访问x,y。 那这个class有什么用?
这里是解决办法: FACTORY方法。
在上面的类中包含以下方法

 public static Test getObject(){ return new Test(); } 

所以现在你可以从外面为这个类创build一个对象。 就像这样…

 Test t = Test.getObject(); 

通过执行其私有构造函数返回类的对象的静态方法称为FACTORY方法

我以为我会在这个post上添加一些关于我所知道的信息。 我们在recent android project广泛使用了这种技术。 您可以使用static method来实例化一个类,而不是creating objects using new operator 。 代码清单:

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

静态方法支持条件对象的创build :每次调用一个构造函数时,一个对象将被创build,但你可能不想要。 假设你想检查一些条件,那么只要你想创build一个新的对象。你不会每次都创build一个新的Vinoth实例,除非你的条件满足。

另一个来自Effective Java的例子。

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

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

Static factory methodsconstructors不同,它们可以返回其返回types的任何子subtypeobject 。 这种灵活性的一个应用是API可以返回对象,而不需要公开它们的类。 以这种方式隐藏实现类会导致非常紧凑的API。

Calendar.getInstance()就是上面的一个很好的例子,它根据locale创build一个BuddhistCalendarJapaneseImperialCalendar或默认一个Georgian

另一个我能想到的例子是Singleton pattern ,在这个Singleton pattern ,你的私有构造函数创build一个自己的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工具箱。 你可以简单地对构造函数进行硬编码,以获得每个构件的具体实现,但是如果你想将一个工具包交换成另一个,那么你就有很多地方需要改变。 通过使用工厂,您可以减less需要更改的代码量。

源自静态工厂的一个优点是API可以在不公开其对象的情况下返回对象。 这导致非常紧凑的API。 在java中,这是通过隐藏大约32个类的Collections类实现的,这使得它的API非常紧凑。

如果要确保只有一个实例要返回要使用的具体类,那么静态工厂方法是很好的。

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

如果你想实现数据库池,那么也可以在不影响其他应用程序的情况下完成。

它可以保护应用程序的其余部分免受您可能向工厂做出的更改,这是目的。

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

静态的

一个成员声明关键字“静态”。

工厂方法

创build并返回新对象的方法

在Java中

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

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

  • Arrays.asList("1","2","3")

  • Collections.synchronizedList(..), Collections.emptyList(), Collections.unmodifiableList(...) (只有一些例子,可以检查mor方法的javadocs示例https://docs.oracle.com/javase/8/docs/ api / java / util / Collections.html )

java.lang.String类也有这样的静态工厂方法

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