第1篇: 讲述了如何创造"缝". "缝"(seam)是须要知道的概念.html
第2篇, 避免在构建对象时写出不易测试的代码.ide
第3篇, 依赖项和迪米特法则.单元测试
本文是第4篇, 将介绍全局状态引发的问题.测试
全局状态, 也能够叫作应用程序状态, 它是一组变量, 这些变量维护着应用程序的高级状态.ui
在程序里, 全局状态可能都存放在一个全局状态对象里, 例如ASP.NET里面的HttpContext; 或者它们多是全局的变量, 这些全局变量在程序的任何地方均可以访问.spa
不论是如何实现的全局状态, 每一个全局状态变量在内存里只有一个实例. 因此若是一个类里更新了全局变量的值, 那么另外一个类访问该变量的时候它的值就是刚才被更新的值.code
有些状况下, 使用全局状态确实有用; 可是若是使用不当, 则会对测试形成很大的影响.htm
就举一个例子吧.对象
有这样一个获取当前登陆用户权限的类, 它使用的是单例模式:blog
这个是典型的单例模式, 它会保证在程序中只返回一个实例, 这里就很少介绍了.
下面这个Service会调用上面这个Auth类:
Auth是单例模式的, 并且还调用了静态方法.
如今的状态是, OfficeService和Auth所包含的全局状态紧密的耦合到了一块儿.
首先应该把单例模式去掉, Auth类只保留两个属性和一个方法:
而后在service里面应该注入IAuth接口并使用:
那么接下来就须要保证这个IAuth不管在程序中注入了多少次, 都是同一个实例.
这时就须要使用依赖注入(DI) 库了. 如今的DI库一般容许指定IoC容器中每对绑定服务的做用范围(Scope), 或叫作生命周期管理.
例如ASP.NET Core内置的IoC容器就内置了这种功能. 在ASP.NET Core 项目的Startup类里, 这样写就能够保证每次请求IAuth的时候只会获得同一个对象实例:
如今这个"单例"的工做是由IoC容器来负责了. 在其它地方正常的注入IAuth使用便可.
先写到这, 本文的概念性内容和更多的例子请参考Angular创始的人这篇文章: http://misko.hevery.com/code-reviewers-guide/flaw-brittle-global-state-singletons/