当您使用控制反转时,您正在帮助您的班级尽可能少地做事。假设您有一些 Windows 服务等待文件,然后对文件执行一系列进程。其中一个过程是将其转换为 ZIP,然后通过电子邮件发送。
public class ZipProcessor : IFileProcessor
{
IZipService ZipService;
IEmailService EmailService;
public void Process(string fileName)
{
ZipService.Zip(fileName, Path.ChangeFileExtension(fileName, ".zip"));
EmailService.SendEmailTo(................);
}
}
当您可以有专门的课程为您完成压缩和发送电子邮件时,为什么这个课程需要实际进行压缩和发送电子邮件?显然你不会,但这只是我的观点:-)
除了不实现 Zip 和 email 之外,为什么类应该知道哪个类实现了服务?如果您将接口传递给此处理器的构造函数,则它永远不需要创建特定类的实例,它会获得完成这项工作所需的一切。
使用 D.I.C.您可以配置哪些类实现某些接口,然后让它为您创建一个实例,它将依赖项注入到类中。
var processor = Container.Resolve<ZipProcessor>();
因此,现在您不仅将类的功能与共享功能明确地分开,而且还阻止了消费者/提供者对彼此有任何明确的了解。这使得阅读代码更容易理解,因为同时需要考虑的因素更少。
最后,在进行单元测试时,您可以传入模拟的依赖项。当您测试 ZipProcessor 时,您的模拟服务只会断言该类尝试发送电子邮件,而不是真正尝试发送电子邮件。
//Mock the ZIP
var mockZipService = MockRepository.GenerateMock<IZipService>();
mockZipService.Expect(x => x.Zip("Hello.xml", "Hello.zip"));
//Mock the email send
var mockEmailService = MockRepository.GenerateMock<IEmailService>();
mockEmailService.Expect(x => x.SendEmailTo(.................);
//Test the processor
var testSubject = new ZipProcessor(mockZipService, mockEmailService);
testSubject.Process("Hello.xml");
//Assert it used the services in the correct way
mockZipService.VerifyAlLExpectations();
mockEmailService.VerifyAllExceptions();
简而言之。你会想要这样做
01:防止消费者明确知道哪个提供者实现了它需要的服务,这意味着当你阅读代码时,一次理解的内容更少。
02:使单元测试更容易。
皮特