揭秘一种微妙的代码坏味道,以及重构之道

本文讲述了在实现IoC容器时如何通过重构,将dependencies的构建与providers同步,简化代码并消除冗余。
摘要由CSDN通过智能技术生成

在实现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,这样使得代码更加简洁和紧凑。

那么现在我们可能就需要去做一个重构。

对应的重构手法如下:

  1. 首先,在 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();
    }
});
  1. 完成 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方法内联
  1. 接下来的关键在于将有关的 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()

于是到此, 我们关于这个坏味道给消灭掉了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值