2.4 应付“全局依赖”
所谓“全局依赖”,是指被测类或被测方法所依赖的合作者是一个“全局单件”,包括C#/Java/C++中的“单件类”(Singleton)和C++中的全局变量和自由方法(实际上, Singleton可视为全局变量在面向对象语言中的变种)。我们下面来看看怎么应对这些情况。
2.4.1 使用“封装全局引用”手法来解除对全局变量和自由方法的依赖
要打破对全局变量和自由方法的依赖,其实基本思想就是:把它们纳入到一个类中,让它们成为一个类的成员变量和成员方法。一旦把全局变量和自由函数封装进了某个类,那么我们就可以继续利用2.2.2节提到的两种手法来引入伪合作者了。
2.4.2 使用“静态调包方法”来解除对单件类的依赖
单件类往往具有3个特点:
(1)单件类的构造函数通常被设为private。
(2)单件类具有一个静态成员变量,该成员变量持有该类的唯一一个实例。
(3)单件类具有一个静态方法,用来提供对单件实例的访问,通常该方法名叫getInstance()。
由于单件类被设计成强制性地在整个程序中只有一份,因此要伪造它比较困难。我们推荐使用“静态调包方法”手法。这个手法的本质是适当打破单件类的单件性约束,把单件类的构造函数改为protected,使我们能够从单件类派生出一个Fake子类,然后为单件类引入一个静态调包函数SupersedeInstance(),以允许单件类中的静态成员变量被“调包”成Fake子类对象。下图表明了这一手法。
同样必须强调的是,在C++中的使用这个手法的时候,必须保证没有资源泄漏。
2.5 如果CollaboratorClass本身就处于继承体系中,怎么办?
先设想一下CollaboratorClass本身存在基类的情况,如下图所示。