软件设计重构秘笈12式-11分解依赖
概念
本文中的“分解依赖” 是指对部分不满足我们要求的类和方法进行依赖分解,通过装饰器来达到我们需要的功能。
意图
分解依赖对部分不满足我们要求的类和方法进行依赖分解,通过装饰器来达到我们需要的功能
正如下面代码所示,如果你要在你的代码中加入单元测试但有一部分代码是你不想测试的,那么你应用使用这个的重构。
下面的例子中我们应用静态类来完成某些工作,
但问题是在单元测试时我们无法mock静态类,所以我们只能引入静态类的装饰接口来分解对静态类的依赖。
从而我们使我们的调用类只需要依赖于装饰接口就能完成这个操作。
案例
public class AnimalFeedingService {
private boolean foodBowlEmpty;
public void feed() {
if (isFoodBowlEmpty()) {
Feeder.replenishFood();
}
}
public boolean isFoodBowlEmpty() {
return foodBowlEmpty;
}
public void setFoodBowlEmpty(boolean foodBowlEmpty) {
this.foodBowlEmpty = foodBowlEmpty;
}
public static class Feeder {
public static void replenishFood() {
// fill up bowl
}
}
}
重构
重构后代码如下,我们添加一个接口和一个实现类,在实现类中调用静态类的方法,所以说具体做什么事情没有改变,改变的只是形式,
但这样做的一个好处是增加了了代码的可测试性。
在应用了分解依赖模式后,我们就可以在单元测试的时候mock一个IFeederService对象并通过AnimalFeedingService的构造函数传递给它。
这样就可以完成我们需要的功能。
public interface IFeederService {
void replenishFood();
}
public class FeederService implements IFeederService {
@Override
public void replenishFood() {
Feeder.replenishFood();
}
public static class Feeder {
public static void replenishFood() {
// fill up bowl
}
}
}
public class AnimalFeedingService {
public IFeederService feederService;
public AnimalFeedingService(IFeederService feederService) {
this.feederService = feederService;
}
private boolean foodBowlEmpty;
public void feed() {
if (isFoodBowlEmpty()) {
feederService.replenishFood();
// more code to feed the animal
}
}
public boolean isFoodBowlEmpty() {
return foodBowlEmpty;
}
public void setFoodBowlEmpty(boolean foodBowlEmpty) {
this.foodBowlEmpty = foodBowlEmpty;
}
}
总结
这个重构在很多时候和设计模式中的一些思想类似,使用中间的装饰接口来分解两个类之间的依赖,对类进行装饰,然后使它满足我们所需要的功能。