2010-07-19 14 views
14

Diese 2-3 letzten Jahre, viele Projekte, die ich sehe, wie Cuyahoga Open Source C# CMS, neigt dazu, persistente und nicht persistente Klassen als Interface zu definieren. Warum? Gibt es einen guten Grund? TDD? Verspottung? Ein Designmuster? ...Warum werden Klassen heutzutage als Schnittstelle definiert?

+7

warum nicht? Sie definieren jedoch keine Klassen als Schnittstellen. Sie setzen sie durch eine Schnittstelle frei. –

+0

@Henk, Ja. Du hast recht. –

Antwort

22

Der Hauptgrund ist, dass dies Techniken wie dependency injection einfacher macht. Dies wiederum ermöglicht eine größere Flexibilität in der Software und eine einfachere Wiederverwendung und Rekombination von existierendem Code. Beispiele dafür, wo dies sinnvoll ist, sind die verschiedenen Formen von Komponententests (wie Sie bereits erwähnt haben), aber auch die meisten anderen Formen der "normalen" Codewiederverwendung.

Ein einfaches Beispiel:

Sagen Sie bitte eine Methode, die emplyoee Gehälter berechnet. Im Rahmen seiner Unterschrift akzeptiert sie ein Objekt, das ihre Leistungen berechnet, sagen wir eine Instanz von BenefitCalculator:

calculateSalary(... BenefitCalculator bc, ...) 

Ursprünglich Ihr Design hat nur eine Klasse BenefitCalculator. Aber später stellt sich heraus, dass Sie mehr als eine Klasse benötigen, z. weil verschiedene Teile der Software unterschiedliche Algorithmen verwenden sollen (vielleicht um verschiedene Länder zu unterstützen, oder weil der Algorithmus benutzerkonfigurierbar sein soll ...). In diesem Fall ist es sinnvoll, die vorhandene Implementierung von BenefitCalculator aufzublähen, um neue Klassen, z. BenefitCalculatorFrance oder BenefitCalculatorSimple usw.

Nun, wenn Sie die Signatur

calculateSalary(... BenefitCalculator bc, ...) 

verwenden, Sie sind so eine Art geschraubt, da Sie nicht verschiedene Implementierungen liefern können. Wenn Sie jedoch

calculateSalary verwenden (... IBenefitCalculator bc, ...)

können Sie haben gerade alle Klassen die Schnittstelle implementieren.

Dies ist eigentlich nur ein Sonderfall der "losen Kopplung": So wenig wie möglich von anderen Teilen des Codes verlangen. Fordern Sie in diesem Fall keine bestimmte Klasse an. Stattdessen verlangen Sie nur, dass bestimmte Methoden existieren, was genau ein Interface tut.

+0

IIRC der Begriff dafür ist [lose Kopplung] (http://en.wikipedia.org/wiki/Loose_coupling). –

+0

@Chris: Ja, ist es. Siehe meine Antwort (letzter Absatz) :-). – sleske

+0

Ah, ich habe das ursprünglich vermisst. –

1

Schnittstellen haben den Vorteil, dass sie unabhängig von der Implementierung sind, was eine gute Sache ist.

3

Zunächst können Sie keine Klasse als Schnittstelle definieren. Ihre Klasse implementiert eine Schnittstelle.

Schnittstellen werden als eine Möglichkeit verwendet, um polymorphes Verhalten zu ermöglichen. Jede Klasse, die die Schnittstelle implementiert, kann ihre eigene Implementierung der in der Schnittstelle definierten Methoden angeben. Nehmen Sie folgendes Beispiel:

Sie schreiben Banking-Software. Ihre Aufgabe ist es, einen Transaktionsprozessor zu schreiben. Jetzt wissen Sie, dass Sie mit verschiedenen Arten von Transaktionen (Einzahlungen, Auszahlungen, Überweisungen) umgehen müssen. Sie könnten Code schreiben, der wie folgt aussieht:

public class TransactionProcessor 
{ 
    public void ProcessDeposit(// Process Deposit); 
    public void ProcessWithdraw(// Process Withdraw); 
    public void ProcessTransfer(// Process Transfer); 
} 

Und jedes Mal, wenn jemand einen neuen Transaktionstyp hinzufügt, müssen Sie Ihre Klasse ändern.Oder Sie könnten:

Jetzt müssen Sie Ihren Code nicht ändern, um eine neue Art von Transaktion zu verarbeiten. Sie brauchen nur Leute, um ihre eigene Klasse zu erstellen, die ITransaction implementiert und Ihre Klasse wird "einfach damit umgehen".

Dies ermöglicht es Ihnen, Implementierungen einer Schnittstelle je nach Ihren Bedürfnissen zu tauschen. Es ermöglicht auch Dinge wie Dependency Injection und Mocking Frameworks für Unit Testing.

Im Allgemeinen ist es jedoch nur eine andere Möglichkeit, Ihren Code flexibler zu machen.

1

In den letzten Jahren sind IoC-Container bei Entwicklern sehr beliebt geworden. Zum Beispiel Unity Container von Microsoft Practices. So können Sie zu Beginn Ihrer Anwendung konkrete Klassen registrieren, die Interfaces implementieren, und dann werden zB alle Klassen, die diese Interfaces in ihren Konstruktoren enthalten, oder ihre mit [Dependency] -Attribut versehenen Eigenschaften gefüllt, wenn Objekte über Instanzen instanziert werden Die Auflösung des Unity-Containers Es ist sehr nützlich in den Anwendungen mit komplizierten Abhängigkeiten, wenn eine Schnittstelle in drei verschiedenen Klassen implementiert werden kann. Und all diese Dinge können nicht ohne die Verwendung von Schnittstellen erreicht werden.

0

Auf einer wirklich langweiligen Ebene können Schnittstellen auch zu einer schnelleren Kompilierung beitragen.

public class A { 
    B b; 
} 

public class B { 
    public int getCount() { 
     return 10; 
    } 
} 

In diesem Fall jedes Mal, interne Änderungen an B gemacht werden, muss der Compiler A zu bestimmen, neu zu bewerten, wenn sie neu kompiliert werden muss.

Stattdessen verwenden wir Schnittstellen:

class A { 
    IB b; 
} 

interface IB { 
    int getCount(); 
} 

class B : IB { 
    public int getCount() { 
     return 10; 
    } 
} 

In diesem Fall A hängt nur von IB. Keine Änderung B erfordert jede Berücksichtigung von A bei der Kompilierung.

Im Maßstab kann dieser Effekt auf die Abhängigkeitsbewertung von Kurzschlüssen die Kompilierung großer Codebasen erheblich beschleunigen. Es ist besonders leistungsfähig, wenn es viele Klassen gibt, die von einer einzelnen Klasse abhängen, die sich stark ändert.

Offensichtlich funktioniert dieser Kompilierzeitvorteil nur, wenn die Klassen keine statische Abhängigkeit von den Implementierungsklassen haben. die folgende tun würde völlig diesen Vorteil besiegen.

class A { 
    IB b = new B(); 
} 

Dies ist, wo Dependency Injection kommt der DI-Container eine B und bieten-A als IB so A doesn würde konstruieren brauche nicht die statische Abhängigkeit.

Verwandte Themen