静态工厂方法代替构造器
读书笔记,仅供参考
ps: 静态工厂方法只是一个返回类的实例的静态方法, 与设计模式中的工厂方法并不一样
public static Boolean valueOf(boolean b) {
return b? Boolean.TRUE: Bolean.FALSE;
}
工厂方法的优势
拥有名称
构造器的参数有时无法确切的描述返回的对象,静态工厂方法可以通过方法名进行表示, 所以当一个类需要多个相同签名(具有相同的方法名,相同个数和相同类型参数)的构造器时,可以使用静态工厂方法代替构造器
不必在每次都创建一个新对象
- 避免创建不必要的重复对象
- 不可变类可以使用预先构建好的实例或者是缓存的实例
有助于类控制实例是否存在,称为实例受控的类(instance-controlled)
实例受控的类
- 可以被确保为 Singleton
- 可以被确保为不可实例化
- 使不可变的类可以确保不存在两个相等的实例,可以使用 == 代替 equals,提升性能
可以返回原返回类型的任何子类型
- 适用于基于接口的框架(接口为静态工厂方法提供了自然返回类型,但是接口不能有静态方法,所有将方法放在一个不可实例化的类中)
例子为 java.utils.Colllections 类,这个类是一个不可实例化的类,静态方法返回的类可以是非公有的。下面的代码是在这个类中找到的符合上面说法的例子。这里也证明了平常使用接口引用实现类的用法。
public static <K, V> Map<K, V> checkedMap(Map<K, V> m,
Class<K> keyType,
Class<V> valueType) {
return new CheckedMap<>(m, keyType, valueType);
}
private static class CheckedMap<K,V>
implements Map<K,V>, Serializable {
}
- 服务提供者框架(Service Provider Framework)
静态工厂返回的对象的类,在编写包含静态工厂方法的类时可以不存在,这构成了服务提供者框架的基础。如 JDBC。
服务提供者框架:多个服务提供者实现一个服务,系统为服务提供者的客户端提供多个实现,并把它们从多个实现中解耦出来。
三个重要组件:
- 服务接口:提供者实现
- 提供者注册API:系统注册实现类
- 服务访问API:客户端获取服务实例
- 服务提供者接口:提供者创建服务的实例(此组件可选)
//服务接口
public interface Service {
}
//服务提供者接口
public interface Provider {
Service newService();
}
//服务注册和方位, 不可实例化的类
public class Services {
private Service(){}
private static final Map<String, Provider> provider =
new ConcurrentHashMap<String, Provider>();
public static final String DEFAULT_PROVIDER_NAME = "<def>";
//提供者注册API
public static void registerDefaultProvider(Provider p) {
registerProvider(DEFAULT_PROVIDER_NAME, p);
}
public static void registerProvider(String name, Provider p) {
providers.put();
}
//服务访问API
public static Service newInstance() {
return newInstance(DEFAULT_PROVIDER_NAME);
}
public static Service newInstance(String name) {
Provider p = providers.get(name);
if(p == null)
throw new IllegalArgumentException("***");
return p.newService();
}
}
这个服务者框架和我现在做的一个项目中一部分有相似的情况,项目是支付平台,支持支付宝和微信,所以有两个 service, AliPayService 和 WechatPayService,他们都实现了 InternalPayService 接口,在使用 spring 的情况下,使用如下代码
@Autowired
private Map<String, InternalPayService> payServices;
可以自动得到一个Map,里面有两个KV,即上面两个实现类,可以说 spring 实现了上面的服务者框架。
在创建参数化类型实例时,使代码变得更加简洁
例子:
Map<String, List<String>> m = new HashMap<String, List<String>>();
假设实现了以下方法
public static <K, V> HashMap<K, V> newINstance() {
return new HashMap<K, V>();
}
第一处的代码可修改为
Map<String, List<String>> m = HashMap.newInstance();
虽然现在的 jdk 已经可以不用再在后面重复类型参数了,精神可以学习。
缺点
类如果不含有公有的或者受保护的构造器,就不能被子类化
这一点可以鼓励使用复合,而不是继承
与其他静态方法没有区别
在查找时不方便