6. 提取并重写调用
和第四条类似, 只不过封装的是变量的访问.
原始代码:
1Class TargetCls
2{
3 private InnerObjCls innerObj = new InnerObjCls();
4
5 public void TargetFun()
6 {
7
8 innerObj.Fun();
9
10 }
11}
重构:
Code
1Class TargetCls
2{
3 private InnerObjCls innerObj = new InnerObjCls();
4
5 public void TargetFun()
6 {
7
8 InnerObjFun();
9
10 }
11
12 protected virtual void InnerObjFun()
13 {
14 innerObj.Fun();
15 }
16}
17
18Class TestCls : TargetCls
19{
20 protected override void InnerObjFun()
21 {
22
23 }
24}
我们把测试方法内部依赖的对象叫'问题对象'. 如果问题对象上只有唯一一个方法的话, 提取并重写调用比较容易, 但如果同一对象上有多个问题方法的话, 我们可能就需要下面的手法了--提取并重写获取方法.
7. 提取并重写获取方法
原始代码:
Code
1Class TargetCls
2{
3 private InnerObjCls innerObj = new InnerObjCls();
4
5 public void TargetFunOne()
6 {
7 innerObj.FunOne();
8 }
9
10 public void TargetFunN()
11 {
12 innerObj.FunN();
13 }
14}
重构:
Code
1interface IInnerObject
2{
3 void FunOne();
4 void FunN();
5}
6
7class InnerObjCls : IInnerObject
8{
9 public void FunOne(){}
10 public void FunN(){}
11}
12
13class FakeInnerObj : IInnerObject
14{
15 public void FunOne(){}
16 public void FunN(){}
17}
18
19Class TargetCls
20{
21 private InnerObjCls innerObj = null;
22
23 protected virtual IInnerObject getInnerObj()
24 {
25 if(innerObj == null)
26 {
27 innerObj = new InnerObjCls();
28 }
29 return innerObj;
30 }
31
32 public void TargetFunOne()
33 {
34 getInnerObj().FunOne();
35 }
36
37 public void TargetFunN()
38 {
39 getInnerObj().FunN();
40 }
41}
42
43Class TestCls : TargetCls
44{
45 protected override IInnerObject getInnerObj()
46 {
47 return new FakeInnerObj();
48 }
49}
类似抽象工厂, 可以把每一个问题方法看做一个产品类, 获取方法返回的是一个具体的工厂. 这种方法从工厂这个接缝解开了大量具体的产品接缝.
8. 定义Set方法; 特征提取, 创建方法对象.
PⅢ, 联系
比较重要的是子类化重写和接口提取. 通常, 应用子类化重写解除测试方法内部调用本类方法的依赖; 应用接口提取解除测试方法内部调用变量对象(其他类型)方法的依赖.
PⅣ, 语录
PⅤ, 备注
本文只记录了适用于面向对象方式的解依赖技术, 不做其他方面(过程, 函数)的介绍.