2008-09-30 8 views
23

Ich stimme zu, dass die Programmierung gegen Schnittstellen eine gute Übung ist. In den meisten Fällen in Java bedeutet "Schnittstelle" in diesem Sinne die Sprachkonstrukt-Schnittstelle, so dass Sie eine Schnittstelle und eine Implementierungsklasse schreiben und dass Sie die Schnittstelle anstelle der Implementierungsklasse die meiste Zeit verwenden.Programmierung mit Interfaces: Schreiben Sie Interfaces für alle Ihre Domain-Klassen?

Ich frage mich, ob dies eine gute Praxis für das Schreiben von Domänenmodellen ist. Also, zum Beispiel, wenn Sie eine Domain-Klasse Kunde und jeder Kunde eine Liste von Aufträgen haben, würden Sie allgemein auch Schnittstellen ICustomer und IOrder schreiben. Und würde der Kunde auch eine Liste von Instruktionen anstelle von Bestellungen haben? Oder würden Sie Schnittstellen im Domänenmodell nur dann verwenden, wenn sie tatsächlich von der Domäne gesteuert werden, z. Sie haben mindestens zwei verschiedene Arten von Bestellungen? Mit anderen Worten: Würden Sie Schnittstellen nur aufgrund von technischen Anforderungen im Domänenmodell verwenden oder nur dann, wenn dies in Bezug auf die tatsächliche Domäne wirklich angemessen ist?

+0

Was ist mit diesem Präfix auf Schnittstellennamen? Seit wann war es in Ordnung, die ungarische Notation zu benutzen? – grom

+0

@grom - Ich hasse es, das auch in Java-Code zu sehen. Es ist eine Konvention von Microsoft COM-Programmierung. –

+3

Sie hassen es in Java zu sehen, aber wie in anderen Sprachen wie C#? Das macht keinen Sinn ... Ich finde es tatsächlich nützlich, wenn ich auf unbekannten Code schaue. Ich kann auf einen Blick sagen, was eine Schnittstelle ist und was eine konkrete Implementierung ist (besonders wenn sie Impl am Ende hinzufügen, welches die Konvention ist, an der ich arbeite) – hhafez

Antwort

26

Schnittstellen schreiben "nur weil" mir als Zeit- und Energieverschwendung erscheint, ganz zu schweigen von einer Verletzung des KISS-Prinzips.

Ich schreibe sie, wenn sie tatsächlich nützlich sind, um gemeinsames Verhalten verwandter Klassen darzustellen, nicht nur als eine ausgefallene Header-Datei.

12

Überarbeiten Sie Ihr System nicht. Wenn Sie feststellen, dass Sie mehrere Arten von Bestellungen haben, und es für angebracht halten, eine Schnittstelle für Bestellungen zu deklarieren, als sie bei Bedarf zu refaktorisieren. Für Domänenmodelle ist die Wahrscheinlichkeit hoch, dass sich die spezifische Schnittstelle im Laufe der Entwicklungszeit stark ändert, daher ist es selten sinnvoll, eine Schnittstelle frühzeitig zu schreiben.

1

Ich verwende normalerweise nur Schnittstellen, wo es bei kleineren Projekten sinnvoll ist. Mein letzter Job hat jedoch ein großes Projekt, bei dem fast jedes Domänenobjekt über eine Schnittstelle verfügt. Es ist wahrscheinlich übertrieben und es ist auf jeden Fall nervig, aber die Art, wie wir testen und Spring für die Abhängigkeitsinjektion verwenden, erfordert es.

1

Wir schreiben meist Webanwendungen mit Wicket, Spring und Hibernate und wir verwenden Schnittstellen für Spring Beans, z. Dienste und DAOs. Für diese Klassen sind Schnittstellen absolut sinnvoll. Aber wir verwenden auch Interfaces für jede einzelne Domain-Klasse und ich denke, das ist einfach zu viel.

1

Auch wenn Sie ziemlich sicher sind, dass es nur einen konkreten Typ eines Modellobjekts geben wird, macht die Verwendung von Interfaces das Mocking und Testen etwas einfacher (aber heutzutage gibt es Framworks, die Ihnen helfen können, automatisch Scheinklassen zu erstellen konkrete Java-Klassen - Mockito, JTestR, Spring, Groovy ...)

Aber ich benutze noch häufiger Schnittstellen für Dienste, da es noch wichtiger ist, sie während des Testens zu verspotten, und Programmierung gegen Schnittstellen hilft Ihnen beim Nachdenken Sachen wie Verkapselung.

8

Schnittstellen sind eine hervorragende Möglichkeit, Komponenten für Komponententests und allgemeine Abhängigkeitsverwaltung zu isolieren. Wenn ich das sage, bevorzuge ich oft abstrakte Klassen, so dass zumindest ein Teil des üblichen Verhaltens dort abgeladen wird, anstatt einige der Duplizierungen zu erzwingen, die Interfaces mit sich bringen. Moderne IDEs machen es schnell und einfach, Schnittstellen zu generieren, so dass sie nicht sind, die viel arbeiten :-)

4

Ich würde empfehlen, bleiben schlank und agil - nichts tun, bis Sie es tun müssen, dann lassen Ihre IDE macht das Refactoring für Sie, wenn Sie es brauchen.

Es ist ziemlich trivial in IDEA/Eclipse, eine konkrete Klasse in eine Schnittstelle zu verwandeln, wenn Sie entscheiden, dass Sie eine brauchen.

Dann Dependency Injection verwenden mit Spring oder Guice, wenn Sie viele Implementierungen der Schnittstelle in die Stellen im Code injizieren Sie ‚neuen‘

1

Schreiben Schnittstellen für Domain-Klassen können dann Sinn, wenn Sie machen‘ Verwenden Sie es für Unit-Tests. Wir verwenden Mock-Objekte im Komponententest. Wenn Sie also eine Schnittstelle für ein Domänenobjekt haben und Ihr Domänenobjekt selbst NICHT bereit ist, kann Ihr Client die Verwendung der Schnittstelle mit Hilfe von Scheinobjekten testen.

Schnittstellen testen auch mehrere Implementierungen Ihrer Schnittstellen für Ihr Domänenmodell. Also, ich denke nicht, dass es immer übertrieben ist.

1

Ich denke, dass der Hauptgrund für die Programmierung gegen Schnittstellen Testbarkeit ist. Daher, für die Domain-Objekte - bleiben Sie einfach bei POJOs oder POC# Os :) usw., d. H. Halten Sie Ihre Klassen von jedem spezifischen Framework, so dass sie von verschiedenen Build-und Laufzeitabhängigkeiten zu verhindern und das ist alles. Erstellen von Schnittstellen für DAOs ist jedoch eine gute Idee.

2

Schreiben Schnittstelle, bevor es benötigt wird (entweder zum Testen oder Architektur) ist ein Overkill.

Darüber hinaus ist das manuelle Schreiben einer Schnittstelle eine Zeitverschwendung. Sie können Resharpers Refactoring "Pull Members" verwenden, um innerhalb von Sekunden ein neues Interface aus der spezifischen Klasse zu erstellen. Andere Refactoring-Tools, die in IDE integriert sind, sollten ebenfalls ähnliche Funktionen haben.

5

Nein, ich verwende nur Schnittstellen für Domain-Objekte, um sie lose gekoppelt zu halten. Für mich ist der Hauptgrund, meinen eigenen Code mit Schnittstellen zu entwickeln, dass ich bei Unit Testing leicht Mocks erzeugen kann. Ich sehe keinen Grund, Domain-Objekte zu verspotten, da sie nicht die gleichen Abhängigkeiten haben wie eine Service-Schicht oder eine DAO-Schicht-Klasse.

Dies bedeutet sicherlich nicht, sich von der Verwendung von Interfaces in Domain Objects zu entfernen. Verwenden Sie gegebenenfalls. Zum Beispiel habe ich in letzter Zeit an einer Webapp gearbeitet, wo verschiedene Arten von Domain-Objekten Permalink-Seiten entsprechen, in denen Benutzer Kommentare hinterlassen können. Jedes dieser Domänenobjekte implementiert nun die Schnittstelle "Commentable". Der gesamte Kommentar-basierte Code wird dann anstelle der Domain-Objekte auf die Commentable-Schnittstelle programmiert.

+1

Ich mag diesen pragmatischen Ansatz. –

+0

Sorry, aber was meinst du "Der gesamte kommentarbasierte Code ist dann auf die Commentable-Schnittstelle programmiert"? Da Sie innerhalb der Schnittstelle keine Implementierungsdetails haben können. – Wuaner

+0

@Wuaner Ich habe diese Antwort vor 8 Jahren geschrieben und habe seither kaum Java angefasst, keine Ahnung was ich meinte. – bpapa

0

Das ist eine andere Sache, die ich im Auge behalten sollte, insbesondere bei generierten Domänen- und DAO-Objekten. Viele Schnittstellen sind einfach zu spezifisch. Angenommen, viele Domänenobjekte haben eine ID und ein Statusfeld. Warum teilen sie sich keine gemeinsame Schnittstelle? Dies hat mich frustriert, ein unnötig flaches (vererbungsweises) Domänenmodell.

1

Wir extrahieren Schnittstellen von allem, nur weil es hilft beim Testen (Mocking) und für Sachen wie AOP. Eclipse kann dies automatisch tun: Refactor-> Interface extrahieren.

Und wenn Sie die Klasse später ändern müssen, können Sie Refactor-> Pull Up ... verwenden, um die benötigten Methoden auf der Schnittstelle aufzurufen.

1

* Ich mache es, weil ich es für die Erstellung von Proxies meiner Domain-Objekte brauche.

4

Eigentlich ist diese Frage ein Beispiel für das häufige Missverständnis über "Programmierung gegen Schnittstellen".

Sie sehen, diese ist ein sehr gutes Prinzip, aber es funktioniert nicht bedeuten, was viele Leute denken, es bedeutet!

"Programm auf eine Schnittstelle, keine Implementierung" (aus dem GoF-Buch) bedeutet nur, dass Sie nicht aus dem Weg zu gehen erstellen separate Schnittstellen für alles. Wenn Sie ein ArrayList-Objekt haben, deklarieren Sie die Variable/Feld/Parameter/Rückgabetyp vom Typ List. Der Client-Code behandelt dann nur den Schnittstellentyp.

In dem Buch "Effective Java" von Joshua Bloch wird das Prinzip deutlicher ausgedrückt, in "Item 52: Auf Objekte über ihre Schnittstellen verweisen". Er sagt auch, in fetten Buchstaben:

es durchaus angemessen ist von einer Klasse auf ein Objekt zu verweisen, anstatt eine Schnittstelle, wenn keine entsprechende Schnittstelle vorhanden ist.

Bei Komponententests hängt die Situation vollständig von den Funktionen des verwendeten Mockingtools ab. Mit meinem eigenen Tool, JMockit, kann ich Komponententests für Code, der Schnittstellen und Dependency Injection verwendet, genauso einfach schreiben wie für Code, der finale Klassen verwendet, die aus dem zu testenden Code stammen.

Also, für mich ist die Antwort: immer Schnittstellen verwenden, die bereits vorhanden sind, aber neue erstellen, wenn es keinen guten Grund gibt, dies zu tun (und Testbarkeit, von selbst, sollte nicht eins sein).