控制反转有助于提高程序的可测试性
控制反转,英文是Inversion of Control,简称IoC。这个概念在JAVA的Spring框架中比较常见,在.NET的开发中,Ioc或者其的变种依赖注入DI(Dependency Injection)是不太常见的。一般来说,类A要使用类B,类A会在其内部对类B进行控制,比较典型的做法就是在类A中创建一个类B的实例;而控制反转,就是把一个已经创建好的类B实例交给类A去控制。
例子:
有一个Member的类,他需要调用一个Web service的客户端接口,在这个类的构造函数里面,创建了一个WebServiceClientA对象。这里的WebServiceClientA类是实现了WebServiceClient接口的。
1 2 3 4 5 6 7 8 | class Member { WebServiceClient client; Member() { client = new WebServiceClientA("10.60.0.11"); } } |
问题来了,对于这个类,我们怎么去测试?在构造函数里面已经初始化了一个WebServiceClientA,并且指定了这个WebServiceClientA的IP是10.60.0.11。那假如说开发环境不能连接到这台服务器上,那么怎么测试。这个问题可以通过对IP地址这个参数写到配置文件里面就能解决,其实这个跟IoC没有什么关系。
1 2 3 4 5 6 7 8 | class Member { WebServiceClient client; Member() { client = new WebServiceClientA(ConfigurationManager.AppSettings["ServerIP"]); } } |
现在又有问题了,如果WebServiceClientA类没有完成,但是此时却要进行测试,怎么办?又假如说WebServiceClientA类是很难被创建的,怎么办?Mock也有劲使不上啊。
其实在构造函数里面是不应该有创建对象的操作,也就是尽可能不要有new操作,我们把WebServiceClient作为构造函数的一个参数,传递进去,这样程序的可测试性就有了提高,这时候可以对WebServiceClient使用Mock对象了。
1 2 3 4 5 6 7 8 | class Member { WebServiceClient client; Member(WebServiceClient c) { client = c; } } |
这跟著名的好莱坞原则(Hollywood Principle)有几分相似,don’t call us, we’ll call you。你不要自己创建一个实现了WebServiceClient接口的对象,我给你传一个。
Related posts:

Leave a Reply