也许你很早就听说过静态工厂了,可是他有什么用呢?下面我将分享自己从书上和项目中得到的一些心得,本文所指的是静态工厂和设计模式种的工厂方法不同。
1、静态工厂与构造器相比有名称
有名称可读性就好
2、复用对象
也许你并不想每次都new一个对象,比如Boolean.valueOf()用的就是这种方法,缓存了一个对象,供调用者获取,而不是每次显示创建。另外,你也许想要做可控的实例,什么是可控呢,简单来说,你不想随便让人构造对象时滥用参数,我在项目中就遇到过这个问题。返回结果的一个类,这个类只能返回三种状态,不想让调用者自己传递状态,往往会出错。这里也就可以考虑一个静态工厂去做受控实例!
3、导出子类
静态工厂可以返回子类,增加api的灵活性,jdk种的Collections类就是这么干的!私有化构造器,
但是可以通过工厂导出子类如同步集合,不可变集合等。这里我贴出代码
下面展示一些 `内联代码片`。
// An highlighted block
public static <E> Set<E> newSetFromMap(Map<E, Boolean> map) {
return new SetFromMap<>(map);
}
4、条件判读
在工厂中你可以根据传递的参数来对条件进行判断,从而产生不同的对象,比如EnumSet就不提供公有的构造器,提供了静态工厂,如果传递的参数(一个枚举)中的元素超过64和小于64是不同的,这里我把代码粘出来
下面展示一些 `内联代码片`。
// a static factory
public static <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);
}
5、方法返回的类可以是在编写该工厂时不存在的
这句话好像有点玄乎,用服务提供者框架来举例吧!服务提供者框架的三个组件:1、服务接口,提供者用来实现
2、提供者注册API,提供者用来注册 3、服务访问API,客户端用来获取服务实例的
场景是这样的:sun公司在制定jdbc规则的时候,倘若mysql还未出现,或者别的未了解的数据库怎么使用呢?
步骤是让提供者去实现服务接口,这些接口是sun约定好的,这时候提供商比如mysql实现这些接口,然后使用者只需要注册使用反射机制Class.forName(真正注册过程的代码mysql封装在com.mysql.jdbc.Drive类中的静态代码块里),一旦Class.forName("com.mysql.jdbc.Drive")即注册上去,具体代码如下
下面展示一些 `内联代码片`
// An highlighted block
package com.mysql.jdbc;
import com.mysql.jdbc.NonRegisteringDriver;
import java.sql.DriverManager;
import java.sql.SQLException;
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
public Driver() throws SQLException {
}
static {
try {
DriverManager.registerDriver(new Driver());
} catch (SQLException var1) {
throw new RuntimeException("Can\'t register driver!");
}
}
}
// List of registered JDBC drivers
private final static CopyOnWriteArrayList<DriverInfo> registeredDrivers = new CopyOnWriteArrayList<DriverInfo>();
public static synchronized void registerDriver(java.sql.Driver driver)
throws SQLException {
if(driver != null) {
registeredDrivers.addIfAbsent(new DriverInfo(driver));
} else {
throw new NullPointerException();
}
println("registerDriver: " + driver);
}
注册完成后,使用者调用服务访问api即可。通过工厂获取!!!
DriverManager.getConnection(“jdbc:mysql:///mydatabase”, “root”, “root”);
下面展示一些 内联代码片
。
// An highlighted block
public static Connection getConnection(String url)
throws SQLException {
java.util.Properties info = new java.util.Properties();
// Gets the classloader of the code that called this method, may
// be null.
ClassLoader callerCL = DriverManager.getCallerClassLoader();
return (getConnection(url, info, callerCL));
}
其实这就是我们想说的第五点!!方法返回的对象的类,未必在编写工厂时就存在!因为这个Connection是从注册的Driver里获取的,实际上返回的是mysql的connection!