Dependancy issue with static utility classes with repository (.NET MVC project)
我有一个带有标准IOC设置的MVC项目,它使用结构映射将存储库注入控制器构造函数。
我还决定要有一个静态的"实用程序"类,在这个类中,我可以有可以由不同的控制器调用的公共方法。例如,我有:
1 2 3 4 5 6 | public static IEnumerable<CountryCode> GetCountryList() { ICountryCodeRepository repo = ObjectFactory.GetInstance<ICountryCodeRepository>(); IEnumerable<CountryCode> countries = repo.GetAll(); return countries; } |
正如您所看到的,它直接从ObjutFr工厂创建一个RePO对象。现在的问题是,当我想对我的控制器进行单元测试时,我可以模拟控制器的RePOS,但不是公用事业类中的RePOS(控制器最终调用)。我确信还有其他原因导致我的实用程序类是错误的,但这就是我目前看到的。我也读过一些东西,说我的设计很差,只是不知道如何修复。
我想让getCountryList()函数接受repo对象
1 | GetCountryList(ICountryCodeRepository _repo) |
调用控制器会将其传入,但这不只是创建另一个依赖关系问题吗,因为所有控制器都必须知道实用程序功能需要什么?
或者可以使用structuremap以某种方式注入这些实用方法吗?
至少你知道你所做的是糟糕的设计是可以的。很好,阅读这篇文章的人也会知道这一点,并且避免犯和你一样的错误。
但现在,您可以在静态类中使用一个提供程序:
1 2 3 4 5 6 7 8 9 10 | public static class Foo { public static Func<ICountryCodeRepository> CountryRepoProvider = () => ObjectFactory.GetInstance<ICountryCodeRepository>(); public static IEnumerable<CountryCode> GetCountryList() { return CountryRepoProvider().GetAll(); } } |
现在在单元测试中,您可以模拟它:
1 | Foo.CountryRepoProvider = () => mocha; |
或者,如果您使用的是ASP.NET MVC 3,而DI框架使用的是依赖关系解析程序,则可以通过至少使其不受DI框架影响来改进此代码:
1 2 3 4 5 | public static IEnumerable<CountryCode> GetCountryList() { var repo = DependencyResolver.Current.GetService<ICountryCodeRepository>(); return repo.GetAll(); } |
现在,在单元测试中,您当然可以编写一个定制的依赖关系解析器,它将吐出您的服务的模拟实例。
现在当你看这些代码的时候,你可能真的会对自己说:我在做什么?我用一个线性方法编写一个静态类,将方法委托给从DI中获取的存储库。当我可以从我的DI框架中获益时,直接在我需要的地方直接注入这个库的实例,然后简单地调用我需要的方法,这有什么意义呢?在一个线性静态方法中,我是什么单元测试?为什么我在浪费时间?
当然,如果您有更复杂的逻辑需要处理,那么您只需编写一个服务层,它将把必要的存储库作为构造函数依赖项,并对它们执行复杂的业务操作。然后,您只需配置DI框架,将那些准备好使用的服务实例注入您的控制器或您需要的任何地方。看到了吗?不需要任何静态类。弱耦合和单元测试友好代码。