在实现IOC容器时候, 我们碰到这样的一个场景, 具体的代码如下
//这个是注入容器
Map<Class<?>, ComponentProvider<?>> providers = new HashMap<>();
//表示根据类获取对应的依赖, 用于做异常检查和循环依赖的控制
Map<Class<?>, List<Class<?>>> dependencies = new HashMap<>();
//对比providers与dependencies的使用场景
providers.put(type, context -> instance);
dependencies.put(type, asList());
providers.put(type,
new ConstructorInjectionProvider<>(type, injectConstructor));
dependencies.put(type,
stream(injectConstructor.getParameters())
.map(Parameter::getType).collect(Collectors.toList()))
通过观察上述代码结构,我们可以注意到 providers 和 dependencies 是相互关联的。当你使用某些数据来构建 providers 时,实际上也在同时构建了相应的 dependencies。
这意味着我们可以在构建 providers 的时候顺带构造出 dependencies就行了,无需额外引入一个独立的 dependencies,这样使得代码更加简洁和紧凑。
那么现在我们可能就需要去做一个重构。
对应的重构手法如下:
- 首先,在 ComponentProvider 中添加一个方法,该方法用于获取相应的依赖信息。
interface ComponentProvider<T> {
T get(Context context);
//添加这个方法, 我们就可以使用providers.getDependenies
//获取对应dependeny
List<Class<?>> getDependenies();
}
因此,原本构建 providers 的操作也需要进行相应调整。在构建 providers 的同时,我们也会顺带着构建相应的 dependencies。
//providers.put(type, context -> instance);
providers.put(type, new ComponentProvider<Type>() {
@Override
public Type get(Context context) {
return object;
}
@Override
public List<Class<?>> getDependencies() {
return asList();
}
});
- 完成 getDependencies 方法,只需将原本用于构造 dependencies 的操作直接迁移过来即可。
一种比较正规的手法如下:
//将原来的操作抽取一个方法
dependencies.put(type, getCollect(injectConstructor));
private static <Type, Implementation extends Type> List<Class<?>> getCollect(Constructor<Implementation> injectConstructor) {
return stream(injectConstructor.getParameters()).map(Parameter::getType).collect(Collectors.toList());
}
//然后在ConstructorInjectionProvider中调用这个方法:
class ConstructorInjectionProvider implements ComponentProvider<T> {
@Override
public List<Class<?>> getDependencies() {
return getColloct(injectConstructor);
}
}
//然后将getClloct方法内联
- 接下来的关键在于将有关的 dependencies 的操作转化成和 providers 相关的操作。在这一步,我们需要仔细观察 dependencies 的使用情境。由于 dependencies 是一个map,它主要有两个使用场景:获取键(key)和获取依赖(dependency)。
//dependencies的构造
providers.put(type, context -> instance);
dependencies.put(type, asList());
//dependencies的使用
dependencies.keySet().forEach(component -> checkDependencies(component, new Stack<>()));
你发现providers与dependencies的key是完全一样的, 所以完全可以使用providers替换:
provides.keySet().forEach(component -> checkDependencies(component, new Stack<>()));
将获取dependencies的操作转换成:
providers.get(component).getDependencies()
于是到此, 我们关于这个坏味道给消灭掉了