什么是“静态工厂”方法?
当前回答
工厂方法:将对象的实例化抽象出来的方法。一般来说,当你知道你需要一个实现接口的类的新实例,但你不知道实现类时,工厂是有用的。
这在处理相关类的层次结构时非常有用,GUI工具包就是一个很好的例子。您可以简单地对每个小部件的具体实现的构造函数进行硬编码调用,但是如果您想要将一个工具包交换为另一个工具包,那么您将有很多地方需要更改。通过使用工厂,您可以减少需要更改的代码数量。
其他回答
当您希望确保只有一个实例将返回要使用的具体类时,静态工厂方法很好。
例如,在一个数据库连接类中,您可能希望只有一个类创建数据库连接,因此如果您决定从Mysql切换到Oracle,您只需更改一个类中的逻辑,而应用程序的其余部分将使用新的连接。
如果您希望实现数据库池,那么也可以在不影响应用程序其余部分的情况下完成。
它保护应用程序的其余部分不受您可能对工厂所做的更改的影响,这就是目的。
它是静态的原因是,如果你想跟踪一些有限的资源(套接字连接或文件句柄的数量),那么这个类可以跟踪已经传递和返回了多少,这样你就不会耗尽有限的资源。
如果类的构造函数是私有的,那么就不能从类的外部为类创建对象。
class Test{
int x, y;
private Test(){
.......
.......
}
}
我们不能从上面的类的外部创建一个对象。所以你不能从类外访问x y。那么这门课有什么用呢? 下面是答案:FACTORY方法。 在上面的类中添加下面的方法
public static Test getObject(){
return new Test();
}
现在你可以在这个类的外部创建一个对象。就像……
Test t = Test.getObject();
因此,通过执行类的私有构造函数返回类对象的静态方法称为FACTORY方法。
我们避免提供对数据库连接的直接访问,因为它们是资源密集型的。因此,我们使用一个静态工厂方法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);
//...
}
}
One of the advantages of the static factory methods with private constructor(object creation must have been restricted for external classes to ensure instances are not created externally) is that you can create instance-controlled classes. And instance-controlled classes guarantee that no two equal distinct instances exist(a.equals(b) if and only if a==b) during your program is running that means you can check equality of objects with == operator instead of equals method, according to Effective java.
The ability of static factory methods to return the same object from repeated invocations allows classes to maintain strict control over what instances exist at any time. Classes that do this are said to be instance-controlled. There are several reasons to write instance-controlled classes. Instance control allows a class to guarantee that it is a singleton (Item 3) or noninstantiable (Item 4). Also, it allows an immutable class (Item 15) to make the guarantee that no two equal instances exist: a.equals(b) if and only if a==b. If a class makes this guarantee, then its clients can use the == operator instead of the equals(Object) method, which may result in improved performance. Enum types (Item 30) provide this guarantee.
摘自Effective Java, Joshua Bloch(第1项,第6页)
静态工厂方法模式是封装对象创建的一种方式。如果没有工厂方法,只需直接调用类的构造函数: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指出,这也可以用来提高可读性。
推荐文章
- Java 8接口方法中不允许“同步”的原因是什么?
- 如何找到Java堆大小和内存使用(Linux)?
- 在哪里放置AutoMapper.CreateMaps?
- 使用Enum实现单例(Java)
- RabbitMQ与通道和连接之间的关系
- buildSessionFactory()配置方法在Hibernate中已弃用?
- Spring MVC -如何获得所有的请求参数在一个地图在Spring控制器?
- 如何在Java中按两个字段排序?
- 由Jon Skeet撰写的《Singleton》澄清
- 文件之间的差异。路径中的分隔符和斜杠
- 在方法参数中使用NotNull注释
- Spring MVC中处理可选参数的@RequestParam
- Tomcat:如何查找正在运行的Tomcat版本?
- “java”、“javaw”和“javaws”之间有什么区别?
- 将Date对象转换为日历对象