你的位置:首页 > Java教程

[Java教程]01、静态工厂方法替代构造器

考虑用静态工厂方法替代构造器


 考虑使用静态工厂方法来替代构造器的原因:

  1. 静态工厂方法有名称:普通的构造器中,参数并不能很好地描述返回对象的特点,代码的阅读性不好。  

考虑下面的程序:

Random random = new Random();
BigInteger integer = BigInteger.probablePrime(3, random);

 该代码的含义是返回一个很有可能是质数并且长度为3的BigInteger对像,这里的长度只的是将整数装换成二进制后的长度;很有可能指的是:不是质数的概率不超过2-100

但是如果使用的是构造函数:BigInteger(int, Random),则很难通过参数来猜测返回的是什么东西。


 2. 使用静态工厂方法不需要每次调用的时候都创建一个新的对象。

如果一些不可变类在使用之前就已经创建好了实例,或者将构建好的实例缓存起来的话,那么在实际使用的时候就能过直接拿过来用,避免了创建不必要的重复对象,下面还是通过已经实际应用的例子来看一下:

Boolean b = Boolean.valueOf(true);  

 这行代码的含义就是创建一个值为true的Boolean对象,我们看一下它的源码:

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

  而TRUE和FALSE的定义如下:

public static final Boolean TRUE = new Boolean(true);public static final Boolean FALSE = new Boolean(false);

  很明显,这两个被直接定义成了不可变类,可以重复使用。如果某些服务里面需要经常创建相同的对象,并且创建对象的代价比较高,则使用这种方法可以显著提高性能。


3. 使用静态工厂方法可以返回原返回类型的任何子类型的对象。

如果API可以返回对象,但同时又不会是对象的类变成公有的,这种方法隐藏了实现类,同时也使API变得简洁。

要说具体实例的话,Java Collections Framework的集合接口中,几乎所有的实现都是通过一个静态工厂方法在一个不可实例化的类中导出。

网络盗图:

 服务提供者框架(Service Provider Framework)

作者提到:静态工厂方法返回的对象所属的类,在编写该静态工厂方法的类时可以不必存在。就是多个服务提供者实现一个服务,系统为服务提供者的客户端提供多个实现,并把他们从多个实现中解耦出来。

服务提供者框架组件:服务接口(Service Interface)、提供者注册API(Provider Registration API)、服务访问API(Service Access API)以及可选组件 服务提供者接口(Service Provider Interface)。

感觉略难懂啊。。。biubiu~

对于JDBC:Connection是服务接口;DriverManager.RegisterDriver就是提供者注册API;DriverManager.getConnection就是服务访问API;Driver就是服务提供者接口。

(PS:是不是吧JDBC的东西忘了?还能手写出来不?赶紧拿出小本本记下来。。。)

public static void main(String[] args) throws ClassNotFoundException, SQLException {
String URL = "jdbc:mysql://127.0.0.1:3306/study?useUnicode=true&characterEncoding=utf-8";
String USER = "root";//用户名
String PASSWORD = "xxxxx";//你的MySQL密码
//1.加载驱动程序
Class.forName("com.mysql.jdbc.Driver");
//2.获得数据库链接
Connection conn = DriverManager.getConnection(URL, USER, PASSWORD);
//3.通过数据库的连接操作数据库,实现增删改查(使用Statement类)
Statement st = conn.createStatement();
ResultSet rs = st.executeQuery("select * from user");
//4.处理数据库的返回结果(使用ResultSet类)
while (rs.next()) {
System.out.println(rs.getString("username") + " " + rs.getInt("age"));
}
//关闭资源
rs.close();
st.close();
conn.close();
}

  稍微有点不太规范哈,不过功能是可以实现的。其中,如果使用了Maven来管理项目的话,需要添加:

<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --> <dependency>  <groupId>mysql</groupId>  <artifactId>mysql-connector-java</artifactId>  <version>5.1.44</version> </dependency>

  下面还有一个具体的模板可供参考,以后可以直接拿过去稍微修改一下就可以用了,完美~:

//这是服务接口 Service Interface
public interface Service {
//各种方法
}

//这是服务提供者接口 Service Provider Interface
public interface Provider {
Service newService();
}

//这是一个不能直接实例化的类用来进行注册和访问的
public class Services {
private Services() { //禁止实例化
}

private static final Map<String, Provider> providers = new ConcurrentHashMap<String, Provider>();
public static final String DEAFULT_PROVIDER_NAME = "default";

//提供着注册API Provider Registration API
public static void registerDefaultProvider(Provider provider) {
registerProvider(DEAFULT_PROVIDER_NAME, provider);
}
public static void registerProvider(String name, Provider provider) {
providers.put(name, provider);
}

//服务访问API Service Access API
public static Service newInstance() {
return newInstance(DEAFULT_PROVIDER_NAME);
}
public static Service newInstance(String name) {
Provider provider = providers.get(name);
if (null == provider) {
throw new IllegalArgumentException("No Provider registered with name" + name);
}
return provider.newService();
}
}

 缺点

任何方法或多或少都会优缺点,没有最好的方法,只有最合适的方法,对一个新的方法要全面了解其优缺点,然后根据自己的实际情况,选择一个最合适的方法。

1、类如果不含公有的或者受保护的构造器的话,就不能够被子类化,没毛病啊~

2、其实静态工厂方法跟其他静态方法实际上没啥区别,毕竟实现方法是类似的嘛~


 

静态工厂方法常用的名称,含义也比较直白:

  • valueOf:一般来说返回的实例跟参数有相同的值。
  • of:比valueOf更简洁,含义类似。
  • getInstance:返回一个具体的实例,可以指定参数进行具体化区别。如果是单例(Singleton)的话,无参数,都返回唯一的实例。
  • getType: 字面意思,返回对象类型,so easy。

 

参考:Effective Java 中文版(第二版)