您的位置:首页 > 编程语言 > Java开发

JAVA 静态工厂方法

2017-05-09 12:36 316 查看
静态工厂方法是一个类产生一个该类实例的静态方法,用于补充或取代类的构造器。

例如 Boolean 中有如下代码段,其中 valueOf 就是一个静态工厂方法。

//...
public static final Boolean TRUE = new Boolean(true);
public static final Boolean FALSE = new Boolean(false);
//...
public static Boolean valueOf(boolean b) {
return (b ? TRUE : FALSE);
}


注意,工厂模式中也有工厂方法,这和这里的静态工厂方法是不一样的。

使用静态工厂方法提供类的实例有以下一些优点。

1)静态工厂方法可以有不同于类名的名字,用户更容易从方法名猜测到其用途,例如 BigInteger 类中有一个静态工厂方法

public static BigInteger probablePrime(int bitLength, Random rnd){
//...
}


该方法为用户返回一个很可能是质数的大整数。

2) 如上述 Boolean 类的方法 valueOf 所表现的, 静态工厂方法不需要新生成一个类的实例,它只是返回一个类的实例,这种方式常常能够提供效率上的改善。静态工厂方法常应用于单例模式中(Effective Java 中推荐使用枚举类型实现单例),保证一个类只被实例化一次,其它地方需要该类的实例是,总是返回同一个实例。

public class Singleton {
// 饿汉模式,JVM 只产生一个静态变量实例,避免线程安全问题,但增大了系统开销
private static final Singleton INSTANCE = new Singleton();
private Singleton() {
//do something here
}
public static Singleton getInstance(){
return INSTANCE;
}
}


另外,在实现不可变类(immutable class)时,也常常用静态工厂方法提供类的实例。

3) 静态工厂方法可以返回当前类的子类实例,从而在不暴露子类的前提下,使用子类的实例,这也是构造方法不具备的功能。

public abstract class EnumSet<E extends Enum<E>> extends AbstractSet<E> implements Cloneable, java.io.Serializable
{
//...
public <E extends Enum<E>> EnumSet<E> noneOf(Class<E> elementType){
Enum<?>[] universe = getUniverse(elementType);
if (universe == null)
throw new ClassCastException(elementType + " not an enum");

if (universe.length <= 64)
return new RegularEnumSet<>(elementType, universe);
else
return new JumboEnumSet<>(elementType, universe);
}
}


抽象类 EnumSet 的一个静态工厂方法,根据枚举类型的大小,返回不同的 EnumSet 的子类实例。

这样做的另一个好处是解耦合,进而实现功能的易于扩展。例如如果将来有一种效率更好的 EnumSet 的子类时,则只需根据条件返回新的子类实例即可,而已使用该方法的代码并不产生做修改。

JDBC 作为一个 Service Provider 框架,也使用了静态工厂方法。 Service Provider 框架有三个必须的组成部分。

Service interface 将服务通过抽象统一声明,供客户端调用。由各个服务提供者(Provider)具体实现

Provider registration API 用于注册已实现了 Service interface 的 Provider,使得客户端可以访问它实现的服务

Service access API 常常通过一个静态工厂方法,让用户可以获得一个 Provider 的实例进行具体的使用。

结合 JDBC 框架

java.sql.Connection
是服务接口(Service interface),它定义了一系列的标准的服务内容,例如
prepareStatement(),commit()
rollback()
等,但却没有实现这些服务。服务提供者 Provider (Mysql,Oracle 等等)可以根据自己的特点实现这些服务内容,只要 Provider 相应的实现类 (例如
oracle.jdbc.driver.PhysicalConnection
类,但我们并不关心这个具体实现类是什么) implements 了 JDBC 的标准接口
java.sql.Connection
既能保证其可用性。

java.sql.DriverManager.getConnection()
就是 Service access API 的静态工厂方法,它根据参数返回对应的 Connection,参数会指明需要返回的 Connection 的实现类。

java.sql.Driver
对应 Service provider interface,Provider 提供该接口的实现类后,在实现类中有一段静态代码,调用
java.sql.DriverManager.registerDriver()
方法将其自身注册到系统中,供用户使用。

static {
try {
if(defaultDriver == null){
defaultDriver = new OracleDriver();
java.sql.DriverManager.registerDriver(defaultDriver);
}
} catch (RuntimeException localRuntimeException) {
} catch (SQLException localSQLException) {
}
}


这段静态代码将在 JVM 加载该类时自动执行,这也是在建立数据库连接前,要显式调用
Class.forName(“oracle.jdbc.driver.OracleDriver”);
加载 Driver 类的原因。

从以上的描述可以看出,静态工厂方法的作用主要是产生一个自身或者子类的实例,从而完善自身的功能和描述。

而工厂模式则是为了解耦,客户端在需要使用产品类的实例的时候,不需要通过 new 或者产品类的静态工厂方法来产生其实例,而是首先创建工厂类,然后通过工厂类提供的方法来得到产品类的实例。关于工厂模式的研究,将在下一篇博文中给出详细的介绍。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java 静态工厂方法