Wenn Sie die Inversion der Kontrolle verwenden, helfen Sie Ihrer Klasse, so wenig wie möglich zu machen. Angenommen, Sie haben einen Windows-Dienst, der auf Dateien wartet und dann eine Reihe von Prozessen für die Datei ausführt. Einer der Prozesse ist es, es in ZIP zu konvertieren und dann per E-Mail zu versenden.
public class ZipProcessor : IFileProcessor
{
IZipService ZipService;
IEmailService EmailService;
public void Process(string fileName)
{
ZipService.Zip(fileName, Path.ChangeFileExtension(fileName, ".zip"));
EmailService.SendEmailTo(................);
}
}
Warum sollte diese Klasse tun müssen, um tatsächlich das Zuziehen und die E-Mailing, wenn Sie Klassen gewidmet haben könnte dies für Sie tun? Natürlich würdest du das nicht, aber das ist nur ein Hinweis auf meinen Punkt :-)
Zusätzlich zu der Implementierung der Zip und E-Mail warum sollte die Klasse wissen, welche Klasse den Dienst implementiert? Wenn Sie Schnittstellen an den Konstruktor dieses Prozessors übergeben, müssen Sie nie eine Instanz einer bestimmten Klasse erstellen, sondern erhalten alles, was sie für die Ausführung der Aufgabe benötigt.
Verwenden eines D.I.C. Sie können konfigurieren, welche Klassen bestimmte Schnittstellen implementieren und dann nur eine Instanz für Sie erstellen. Dadurch werden die Abhängigkeiten in die Klasse eingefügt.
var processor = Container.Resolve<ZipProcessor>();
So, jetzt haben nicht nur sauber Sie die Klasse der Funktionalität von gemeinsamen Funktionen getrennt, aber Sie haben auch die Verbraucher/Anbieter von mit einer expliziten Kenntnis voneinander verhindert. Dies macht das Lesen von Code leichter verständlich, da weniger Faktoren gleichzeitig berücksichtigt werden müssen.
Schließlich, wenn Unit-Tests können Sie verspottet Abhängigkeiten übergeben. Wenn Sie Ihren ZipProcessor testen, werden Ihre verspotteten Dienste lediglich bestätigen, dass die Klasse versucht hat, eine E-Mail zu senden, anstatt sie wirklich zu senden.
//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();
Also kurz gesagt. Sie möchten es tun, um 01: Verhindern Sie, dass Verbraucher explizit wissen, welcher Anbieter die Dienste implementiert, die es benötigt, was bedeutet, dass weniger zu verstehen ist sofort beim Lesen von Code. 02: Erleichtern Sie das Testen von Einheiten.
Pete
aber was ist mit keiner Konfiguration (wie in Google Guice) - wie geben Sie die "Komponentenrollen"? – JohnIdol
Das letzte Mal, als ich Guice angeschaut habe, fehlte der Aspekt "convention over configuration", den man durch das Mischen von Annotationen, XML und Rollen erhalten konnte, was auch der Grund ist, warum ich Spring javaconfig nicht verwende. Ich bevorzuge das gemischte Paradigma. Das Ersetzen von XML durch Code, der das Gleiche tut, schneidet mir nichts an, vielleicht ist es nur, dass ich engstirnig bin, aber ich kann nicht sehen, wie Code-basierte Konfiguration für mich einen Mehrwert schaffen würde. Aber ich weiß nicht, ob Sie ein Convention-basiertes Setup in Guice erreichen können. – krosenvold