什么是“静态工厂”方法?
当前回答
静态工厂方法模式是封装对象创建的一种方式。如果没有工厂方法,只需直接调用类的构造函数:Foo x = new Foo()。使用这种模式,你可以调用工厂方法:Foo x = Foo.create()。构造函数被标记为private,因此只能从类内部调用它们,而工厂方法被标记为静态,因此可以在没有对象的情况下调用它。
这种模式有几个优点。一个是工厂可以从许多子类(或接口的实现者)中选择并返回。通过这种方式,调用者可以通过参数指定所需的行为,而不必知道或理解潜在的复杂类层次结构。
Another advantage is, as Matthew and James have pointed out, controlling access to a limited resource such as connections. This a way to implement pools of reusable objects - instead of building, using, and tearing down an object, if the construction and destruction are expensive processes it might make more sense to build them once and recycle them. The factory method can return an existing, unused instantiated object if it has one, or construct one if the object count is below some lower threshold, or throw an exception or return null if it's above the upper threshold.
根据维基百科上的文章,多个工厂方法还允许对相似的参数类型进行不同的解释。通常构造函数与类具有相同的名称,这意味着具有给定签名的构造函数只能有一个。工厂没有那么多限制,这意味着你可以有两个不同的方法接受相同的参数类型:
Coordinate c = Coordinate.createFromCartesian(double x, double y)
and
Coordinate c = Coordinate.createFromPolar(double distance, double angle)
Rasmus指出,这也可以用来提高可读性。
其他回答
我想我会在这篇文章中添加一些我所知道的东西。我们在最近的android项目中广泛使用了这种技术。除了使用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()是一个很好的例子,它根据地区创建一个佛教日历,日本帝国日历或默认的格鲁吉亚日历。
另一个例子,我认为是单例模式,你使你的构造函数私有创建一个自己的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;
}
}
这一切都归结为可维护性。最好的方式是,无论何时使用new关键字创建对象,都是将所编写的代码耦合到实现中。
The factory pattern lets you separate how you create an object from what you do with the object. When you create all of your objects using constructors, you are essentially hard-wiring the code that uses the object to that implementation. The code that uses your object is "dependent on" that object. This may not seem like a big deal on the surface, but when the object changes (think of changing the signature of the constructor, or subclassing the object) you have to go back and rewire things everywhere.
如今,由于依赖注入需要大量的样板代码,而这些代码本身维护起来有点困难,工厂在很大程度上被忽略了。依赖注入基本上等同于工厂,但允许你以声明的方式(通过配置或注释)指定你的对象如何连接在一起。
当您希望确保只有一个实例将返回要使用的具体类时,静态工厂方法很好。
例如,在一个数据库连接类中,您可能希望只有一个类创建数据库连接,因此如果您决定从Mysql切换到Oracle,您只需更改一个类中的逻辑,而应用程序的其余部分将使用新的连接。
如果您希望实现数据库池,那么也可以在不影响应用程序其余部分的情况下完成。
它保护应用程序的其余部分不受您可能对工厂所做的更改的影响,这就是目的。
它是静态的原因是,如果你想跟踪一些有限的资源(套接字连接或文件句柄的数量),那么这个类可以跟踪已经传递和返回了多少,这样你就不会耗尽有限的资源。
我们避免提供对数据库连接的直接访问,因为它们是资源密集型的。因此,我们使用一个静态工厂方法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);
//...
}
}
与构造函数不同,具有名称,可以阐明代码。 不需要在每次调用时创建一个新对象-对象 如果需要,可以缓存和重用。 可以返回其返回类型的子类型-特别是,Can 返回调用方不知道其实现类的对象。 这是许多框架中非常有价值和广泛使用的特性 它们使用接口作为静态工厂方法的返回类型。
标准:/ / www.javapractices.com/topic/TopicAction.do ? Id = 21
推荐文章
- 指定的子节点已经有一个父节点。你必须先在子对象的父对象上调用removeView() (Android)
- 对于一个布尔字段,它的getter/setter的命名约定是什么?
- 如何获得当前屏幕方向?
- 如何在Android中渲染PDF文件
- 如何计算一个元素在列表中出现的次数
- c++中类似于java的instanceof
- 我如何解决错误“minCompileSdk(31)指定在一个依赖的AAR元数据”在本机Java或Kotlin?
- 如何POST表单数据与Spring RestTemplate?
- Mockito中检测到未完成的存根
- 我应该如何复制字符串在Java?
- “while(true)”循环有那么糟糕吗?
- 这个方法签名中的省略号(…)是干什么用的?
- Java:如何测试调用System.exit()的方法?
- 带有返回类型的Java方法在没有返回语句的情况下编译
- Java“此语言级别不支持lambda表达式”