什么是“静态工厂”方法?
什么是“静态工厂”方法?
Answers:
我们避免直接访问数据库连接,因为它们消耗大量资源。因此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);
//...
}
}
该静态工厂方法模式是一种封装对象的创建。如果没有工厂方法,则只需直接调用类的构造函数:Foo x = new Foo()
。使用这种模式,您可以改为调用factory方法: 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所指出的,这也可以用来提高可读性。
注意!“该静态工厂方法是不一样的工厂方法模式”(三)有效的Java,约书亚·布洛克。
工厂方法:“定义一个用于创建对象的接口,但是让实现该接口的类决定要实例化哪个类。工厂方法使一个类将实例化推迟到子类。”(c)GoF。
“静态工厂方法只是返回类实例的静态方法。” (c)有效的Java,约书亚·布洛赫(Joshua Bloch)。通常,此方法在特定的类中。
区别:
静态工厂方法的关键思想是获得对对象创建的控制,并将其从构造函数委托给静态方法。要创建对象的决定就像在方法之外在“抽象工厂”中做出的决定一样(通常,但并非总是如此)。而Factory Method的关键(!)想法是委托在Factory Method中创建要创建的类的实例的决定。例如,经典的Singleton实现是静态工厂方法的一种特殊情况。常用的静态工厂方法示例:
可以通过静态工厂方法提高可读性:
比较
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();
private Foo(boolean withBar){/*..*/}
public static Foo createWithBar(){return new Foo(true);}
public static Foo createWithoutBar(){return new Foo(false);}
- 与构造函数不同,它们具有可以澄清代码的名称。
- 无需在每次调用时都创建一个新对象-可以根据需要缓存和重用对象。
- 可以返回其返回类型的子类型-特别是可以返回调用者未知其实现类的对象。这是在许多使用接口作为静态工厂方法的返回类型的框架中非常有价值且广泛使用的功能。
归结为维护性。最好的解决方法是,每当您使用new
关键字创建对象时,便会将正在编写的代码耦合到实现上。
工厂模式使您可以将创建对象的方式与处理对象的方式分开。当使用构造函数创建所有对象时,实际上是在将使用该对象的代码硬连线到该实现。使用您的对象的代码“依赖于”该对象。从表面上看,这似乎没什么大不了,但是当对象改变时(想改变构造函数的签名,或子类化对象),则必须返回并重新布线。
如今,工厂很大程度上被抛在一边,而赞成使用依赖注入,因为它们需要大量样板代码,而这些代码实际上很难维护。依赖注入在本质上与工厂等效,但是可以让您指定如何以声明方式(通过配置或注释)将对象连接在一起。
如果类的构造函数是私有的,则您无法从其外部为类创建对象。
class Test{
int x, y;
private Test(){
.......
.......
}
}
我们不能从外部为上述类创建对象。因此,您不能从类外部访问x,y。那么该类的用途是什么?
这是答案:FACTORY方法。
在上面的类中添加以下方法
public static Test getObject(){
return new Test();
}
因此,现在您可以从其外部为该类创建一个对象。就像这样
Test t = Test.getObject();
因此,通过执行其私有构造函数返回类的对象的静态方法称为FACTORY方法
。
Static Factory Method
对于公共构造函数,我们有什么好处吗?
我以为我会对我所知道的内容加一些启发。我们在电脑中广泛使用了这种技术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。
Calendar.getInstance()是一个很好的例子为上述的,它创建取决于区域设置的BuddhistCalendar
,JapaneseImperialCalendar
或通过默认的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个类,这使其Collection API非常紧凑。
使用私有构造函数的静态工厂方法的优点之一(必须为外部类限制对象的创建,以确保不会在外部创建实例)是可以创建实例控制的类。并且实例控制的类保证程序运行期间不存在两个相等的不同实例(a.equals(b),并且仅当a == b时),这意味着您可以使用==运算符而不是equals方法检查对象的相等性。,根据有效Java。
静态工厂方法从重复调用返回相同对象的能力允许类对任何时刻存在的实例保持严格的控制。据说这样做的类是实例控制的。编写实例控制的类有多种原因。实例控件允许类保证它是单例(项目3)或不可实例化(项目4)。而且,它允许不可变的类(第15项)保证不存在两个相等的实例:a.equals(b)当且仅当a == b时。如果一个类保证了这一点,那么它的客户可以使用==运算符而不是equals(Object)方法,这可能会提高性能。枚举类型(项30)提供了此保证。
来自有效Java的Joshua Bloch(第1页,第1项)
静态的
用关键字“ static”声明的成员。
工厂方法
创建和返回新对象的方法。
在Java中
编程语言与“静态”的含义有关,而与“工厂”的定义无关。
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(...)