Das "I"-Prefix bei Interfaces
-
finix schrieb:
mathik schrieb:
rapso schrieb:
ich habe fuer jedes interfaces zu meinen implementationen ebenfalls eine normale klasse.
was erhoffst du dir dadurch, indem du das für jede klasse machst?
Eine Trennung von Typ und Klasse?
d.h. deiner meinung nach ist typ=interface und implementierung=klasse??
das ist ja auch korrekt, nur nicht vollständig. eine klasse hat genauso wie ein interface eine schnittstelle: die öffentlichen operationen.wie schon bereits gesagt: ein typ aus der analyse kann technisch durch ein oder mehrere interfaces und (abstrakten) klassen realisiert werden. genauso können ein interface und eine (abstrake) klasse mehrere typen realisieren. für mich sind das somit technische konzepte um typen programmtechnisch abzubilden; evtl. sogar vergleichbar mit for- vs. while-schleifen

deshalb finde ich es übertrieben konsequent für jede klasse ein interface zu erstellen, auch wenn es nur eine implementierung gibt. das verkompliziert den code nur unnötig. außerdem gibt es eine refactoring-operation: "extract-interface", mit der man zu einer klasse durch knopfdruck ein interface generieren kann und alle klienten darauf automatisch angepasst werden.
-
Blue-Tiger schrieb:
schlauher als ihr schrieb:
in eclipse wurde das so gemacht, weil zu jedem interface eine implementierende klasse mit dem selben namen existiert: IPath <- Path
IMO is diese namensgebung besser als Path <- PathImpl oder DefaultPathGleiche Frage: wozu brauchen die ein Interface, wenn sie doch nur 1 Implementierung haben? Und wenn sie dem Benutzer die Moeglichkeit bieten wollen, eigene Implementierungen zur Verfuegung zu stellen und deswegen Interfaces anbieten, dann ja, dann find ich "DefaultXyz" ist ein sehr guter Name fuer die Standardimplementierung von Xyz.
Also ich kann mir das durchaus vorstellen, vor allem, wenn ich bedenke, dass ich gerade System-Resourcen (z.B: eben Path) bzw. Objekte die System-Resourcen verwenden (z.B: Zugriffsobjekte für die Datenbankschicht) in Komponententests mocken möchte. Bei mir geht das teilweise schon so weit, dass ich nur noch die Schnittstelle habe und mir aus dieser (und einigen zusätzlichen Metadaten) die Implementierung generieren lasse.
-
dsf232sdg schrieb:
Blue-Tiger schrieb:
schlauher als ihr schrieb:
in eclipse wurde das so gemacht, weil zu jedem interface eine implementierende klasse mit dem selben namen existiert: IPath <- Path
IMO is diese namensgebung besser als Path <- PathImpl oder DefaultPathGleiche Frage: wozu brauchen die ein Interface, wenn sie doch nur 1 Implementierung haben? Und wenn sie dem Benutzer die Moeglichkeit bieten wollen, eigene Implementierungen zur Verfuegung zu stellen und deswegen Interfaces anbieten, dann ja, dann find ich "DefaultXyz" ist ein sehr guter Name fuer die Standardimplementierung von Xyz.
Also ich kann mir das durchaus vorstellen, vor allem, wenn ich bedenke, dass ich gerade System-Resourcen (z.B: eben Path) bzw. Objekte die System-Resourcen verwenden (z.B: Zugriffsobjekte für die Datenbankschicht) in Komponententests mocken möchte. Bei mir geht das teilweise schon so weit, dass ich nur noch die Schnittstelle habe und mir aus dieser (und einigen zusätzlichen Metadaten) die Implementierung generieren lasse.
Hmm.... ok, die Autogenerierung klingt sinnvoll
Aber warum ists fuer Komponententests sinnvoll, bei nur 1 Implementierung eine Interface/Implementierungstrennung einzufuehren? Ist das nicht unnoetige Komplexitaet?
-
Blue-Tiger schrieb:
Hmm.... ok, die Autogenerierung klingt sinnvoll
Aber warum ists fuer Komponententests sinnvoll, bei nur 1 Implementierung eine Interface/Implementierungstrennung einzufuehren? Ist das nicht unnoetige Komplexitaet?Natürlich lassen sich dadurch die Implementierungen ansich nicht einfacher testen, aber gerade wenn Abhängigkeiten zu anderen Komponenten bestehen, lassen sich diese dann, wenn auch nur beim Testen, ersetzen um eine isolierte Ausführung zu gewährleisten. Mock-Objekte implementieren Schnittstellen, enthalten aber statt Geschäftslogik die notwendige Testlogik (also beispielsweise einige Assertions). Am besten siehst du dir dazu aber die Theorie zu Mock-Objekten an.
-
testbarkeit ist aber immer noch kein argument dafür, für jede klasse ein interface zu machen. mock-objekte können nämlich - zumindest bei java (z.b. mit easymock) - auch für klassen erstellt werden.
mich stört ja auch nicht, dass interfaces für schnittstellen von komponenten verwendet werden, oder dass sie in maßen verwendet werden. mich stört eigentlich nur das "I"-prefix. denn ich will auf typen operieren - diese werden meistens durch interfaces repräsentiert - und deren name ist dann durch dieses "Iiihhh" vermurkst. "PathImpl" oder "DefaultPath" oder "IPath" (steht jedoch für PathImplementation) finde ich besser, da diese durch das interface "Path" an der schnittstelle der komponente sowieso verdeckt werden.
-
mathik schrieb:
testbarkeit ist aber immer noch kein argument dafür, für jede klasse ein interface zu machen. mock-objekte können nämlich - zumindest bei java (z.b. mit easymock) - auch für klassen erstellt werden.
mich stört ja auch nicht, dass interfaces für schnittstellen von komponenten verwendet werden, oder dass sie in maßen verwendet werden. mich stört eigentlich nur das "I"-prefix. denn ich will auf typen operieren - diese werden meistens durch interfaces repräsentiert - und deren name ist dann durch dieses "Iiihhh" vermurkst. "PathImpl" oder "DefaultPath" oder "IPath" (steht jedoch für PathImplementation) finde ich besser, da diese durch das interface "Path" an der schnittstelle der komponente sowieso verdeckt werden.
Ich habe auch nie jemandem empfohlen ein Interface für jede Klasse zu erstellen. Für typische Beans (normale POJOs sind gemeint, nicht diese GUI Beans) - wenn wir schon den Bezug zu Java herstellen - wäre dies sinnlos.
Auch wenn einige meiner Hierachien anfangs nur aus einem Interface und der Implementierung bestehen, verändern sich diese eben mit der Zeit, wobei nicht notwendigerweise eine weitere konkrete Implementierung dazukommen muss. Decorator-Objekte, die den Aufruf modifizieren, und dergleichen (irgendwie also Aspektorientierung für "arme") ergeben sich gerne erst im Lauf der Entwicklung.
Weiters denke ich schon, dass Testbarkeit sehr wohl ein Argument für die Verwendung von Interfaces ist, weil sich auch mit Projekten wie easymock nicht alles mocken lässt.
-
Blue-Tiger schrieb:
Und wenn sie dem Benutzer die Moeglichkeit bieten wollen, eigene Implementierungen zur Verfuegung zu stellen und deswegen Interfaces anbieten, dann ja, dann find ich "DefaultXyz" ist ein sehr guter Name fuer die Standardimplementierung von Xyz.
Kleine Anmerkung noch zu dieser Aussage:
So generell würde ich das auch nicht sagen, denn gerade beim Beispiel Path kann das meiner Meinung nach zu unnötiger Verwirrung führen. Bei DefaultPath und Path als Typen würde ich intuitiv nicht darauf schließen, dass das eine das andere implementiert. Wenn man es übersetzt, wird es vielleicht deutlicher, dass man ihnen unterschiedliche Bedeutungen zuschreibt: Standardpfad und Pfad.
-
sdf82742sf schrieb:
Auch wenn einige meiner Hierachien anfangs nur aus einem Interface und der Implementierung bestehen, verändern sich diese eben mit der Zeit, wobei nicht notwendigerweise eine weitere konkrete Implementierung dazukommen muss. Decorator-Objekte, die den Aufruf modifizieren, und dergleichen (irgendwie also Aspektorientierung für "arme") ergeben sich gerne erst im Lauf der Entwicklung.
das ist ja auch ein vernünftiges vorgehen. ich mach es ja auch nicht anders.

sdf82742sf schrieb:
Weiters denke ich schon, dass Testbarkeit sehr wohl ein Argument für die Verwendung von Interfaces ist, weil sich auch mit Projekten wie easymock nicht alles mocken lässt.
auf jeden fall. nur wie gesagt, ich finde es übertrieben für jede klasse ein interface zu erstellen. aber du machst das ja auch anscheinend nicht.
BTW: mich stört ja immer noch dieses "Iihh"-prefix... wer hat das erfunden?

-
mathik schrieb:
BTW: mich stört ja immer noch dieses "Iihh"-prefix... wer hat das erfunden?

Ich nehme an, dass das ein Überbleibsel aus der ungarischen Notation sein wird. Der Hintergedanke dabei ist meiner Meinung nach einfach nachzuvollziehen, da es gerade in größeren Projekten wie Eclipse nicht egal ist ob der Typ eine Klasse, eine abstrakte Klasse oder ein Interface ist. Grundprinzip ist ja, dass man immer gegen Interfaces programmieren soll und um das einfach überprüfen zu können dient das "I"-Präfix um Interfaces von den restlichen Typen schnell unterscheiden zu können. Ich würde zwar leitenden Entwicklern nicht widersprechen, wenn sie mir diese Namenskonvention vorschreiben, da ich sie eben, wie bereits erwähnt, nachvollziehen kann, von selbst aus halte ich sie aber auch nicht ein (sofern ich nicht gerade C# programmiere, denn dann natürlich schon).
-
Da I-Präfix wird auch von MS für die COM-Specs benutzt. COM-Interfaces fangen auch mit I an. Hat halt IBM für Eclipse mit übernommen.
-
Blue-Tiger schrieb:
rapso schrieb:
ich habe fuer jedes interfaces zu meinen implementationen ebenfalls eine normale klasse.
Wozu dann ueberhaupt das Interface? Wenn du fuer jedes Interface nur 1 Implementation hast, wozu dann ueberhaupt das Interface?
ein interface ist eine reine schnittstellenbeschreibung bzw schnittstelle, sie enthaellt keine interna z.b. inlinefunktionen, member, friends etc. die fuer die anwender der klasse nicht noetig sind.
mathik schrieb:
rapso schrieb:
ich habe fuer jedes interfaces zu meinen implementationen ebenfalls eine normale klasse.
was erhoffst du dir dadurch, indem du das für jede klasse machst? eine klasse hat doch auch eine schnittstelle, nämlich die öffentlichen operationen. der rest ist für die klienten tabu und wird von denen verborgen ("jede klasse sollte wie ein eisberg sein: man sieht nur die spitze")
diese abstrahierung von schnittstelle und implementierung macht man um zu ermoeglichen die implementierung zu aendern ohne das interface aendern zu muessen. das waere rein theoretisch auch machbar wenn man die klassenbeschreibung der implementierung weitergibt, jedoch ist es einfach sauberer eine schnittstellendefinition auf beiden seiten zu haben, sodass sich auf der einen seite jemand um die interner kuemmern kann, waehrend die andere seite die schnittstelle verwendet ohne das ungewollte abhaengigkeiten entstehen die mittels der implementierungs-header moeglich sind.
-
Artchi schrieb:
Da I-Präfix wird auch von MS für die COM-Specs benutzt. COM-Interfaces fangen auch mit I an. Hat halt IBM für Eclipse mit übernommen.
also ist microsoft wieder schuld!? die können sich wohl nicht endgültig von deren ungarischen notation verabschieden, obwohl bei den .NET coding style guides folgendes zu finden ist:
- Do not use Hungarian notation
- Do not prefix enums, classes, or delegates with any letterund dann steht:
- Do prefix interfaces names with “I”

@rapso
interfaces sind ja auch schön und gut und man verwendet besser mehr von denen als zu wenig. für jede klasse ein interface zu erzeugen, auch wenn diese nur innerhalb der komponente verwendet wird und sonst keiner kennt, finde ich einfach übertrieben und verkompliziert einfach unnötig den code.
-
mathik schrieb:
interfaces sind ja auch schön und gut und man verwendet besser mehr von denen als zu wenig. für jede klasse ein interface zu erzeugen, auch wenn diese nur innerhalb der komponente verwendet wird und sonst keiner kennt, finde ich einfach übertrieben und verkompliziert einfach unnötig den code.
fuer jede fuer die es moeglicherweise alternativ implementierungen geben kann wird es gemacht, das ist auch sinnig.
-
rapso schrieb:
mathik schrieb:
interfaces sind ja auch schön und gut und man verwendet besser mehr von denen als zu wenig. für jede klasse ein interface zu erzeugen, auch wenn diese nur innerhalb der komponente verwendet wird und sonst keiner kennt, finde ich einfach übertrieben und verkompliziert einfach unnötig den code.
fuer jede fuer die es moeglicherweise alternativ implementierungen geben kann wird es gemacht, das ist auch sinnig.
d.h. nun doch nicht für jede klasse!?

solche begründungen, wie "weil es in zukunft vielleicht benötigt wird" finde ich jedoch gefährlich. bei agiler entwicklung soll man ja möglichst alles so einfach wie möglich halten und bei bedarf refaktorisieren. man sollte also nicht zu weit in die zukunft schauen.
-
mathik schrieb:
bei agiler entwicklung soll man ja möglichst alles so einfach wie möglich halten und bei bedarf refaktorisieren. man sollte also nicht zu weit in die zukunft schauen.
Wenn man allerdings von XP ausgeht, als agile Entwicklungsmethode, fängt man ohnehin beim Testen an - Testen scheint irgendwie mein Steckenpferd zu sein - und da arbeite ich eben von vornherein lieber mit "leichtgewichtigen" Schnittstellen als "schwergewichtigen" Implementierungen, sozusagen salop formuliert.
-
dsf24534sd schrieb:
mathik schrieb:
bei agiler entwicklung soll man ja möglichst alles so einfach wie möglich halten und bei bedarf refaktorisieren. man sollte also nicht zu weit in die zukunft schauen.
Wenn man allerdings von XP ausgeht, als agile Entwicklungsmethode, fängt man ohnehin beim Testen an - Testen scheint irgendwie mein Steckenpferd zu sein - und da arbeite ich eben von vornherein lieber mit "leichtgewichtigen" Schnittstellen als "schwergewichtigen" Implementierungen, sozusagen salop formuliert.
Aber du siehst doch gar nicht ob der Typ jetzt "schwergewichtig" oder "leichtg." ist. Du siehst doch in beiden Fällen nur die public-Methoden.
Ah jetzt versteh ich. Mal ein Beispiel:
Iterable i = new MeineListe(); Comparable c = new MeineListe(); MeineListe ml = new MeineListe();Bei i siehst du nur den Teil von Iterable und bei c siehst du nur den Teil von Comparable. Bei ml aber siehst du beide Schnittstellen und zusätzliche von der Klasse MeineListe.
Na gut, aber was bringt es mir zu wissen ob Iterable und Comparable Interfaces sind? Eigentlich doch nichts.
Was bringt es mir jetzt eine IMeineListe zu haben?
IMeineListe ia = new MeineListe(); IMeineListe ib = new MeineListeTest();Ist das gleiche wie:
MeineListe mla = new MeineListe(); MeineListe mlb = new MeineListeTest();In beiden Fällen sehe ich die Schnittstelle der Klasse MeineListe.
-
DEvent schrieb:
Aber du siehst doch gar nicht ob der Typ jetzt "schwergewichtig" oder "leichtg." ist. Du siehst doch in beiden Fällen nur die public-Methoden. [...] Na gut, aber was bringt es mir zu wissen ob Iterable und Comparable Interfaces sind? Eigentlich doch nichts.
Die transitiven Abhängigkeiten, die eine konkrete Implementierung zwangsweise mit sich zieht, sind jene, die den Typ "schwergewichtig" machen, nicht die öffentliche Schnittstelle. Insofern macht es sehr wohl einen Unterschied ob es sich beim Typ um ein Interface oder eine Klasse handelt.
-
Ja, wenn die Klasse eine Implementierung hat, haste Recht. Aber Klassen können auch pure virtual sein.
class A { public: virtual void foo() = 0; };Absolut keine Abhängigkeit zu irgendwelchen externen Typen. Was bringt es mir jetzt, wenn ich daraus ein "Interface" mache? Es ist doch schon ein Interface.
Übrigens, wartet mal ab, was C++2009 bringt, da wird es die sogenannten Concepts geben. Das wird auch eine weitere Variante von Schnittstellen-Vorgaben/-Vereinbarungen sein. In dem Fall zwar auf Templates zugeschnitten, aber es zeigt, das was man Ende will, das gleiche ist.
-
Artchi schrieb:
Ja, wenn die Klasse eine Implementierung hat, haste Recht. Aber Klassen können auch pure virtual sein.
class A { public: virtual void foo() = 0; };Absolut keine Abhängigkeit zu irgendwelchen externen Typen. Was bringt es mir jetzt, wenn ich daraus ein "Interface" mache? Es ist doch schon ein Interface.
Ganz ehrlich, ich habe kein Interesse an einer Diskussion "Interfaces vs rein-virtuellen Klassen", insofern schließe ich mich einfach deiner eigenen Aussage aus: "Es ist doch schon ein Interface". Ich bezog mich bei meinen Aussagen auf eine generelle Terminologie, die eben nicht auf eine einzige Sprache eingeschränkt ist , und nachdem C++ ja keine Interfaces kennt, ist dieses Konstrukt für mich quasi ein Interface. Dadurch ergibt sich auch, dass sich unsere Aussagen eher decken als widersprechen.
-
df23sdg schrieb:
DEvent schrieb:
Aber du siehst doch gar nicht ob der Typ jetzt "schwergewichtig" oder "leichtg." ist. Du siehst doch in beiden Fällen nur die public-Methoden. [...] Na gut, aber was bringt es mir zu wissen ob Iterable und Comparable Interfaces sind? Eigentlich doch nichts.
Die transitiven Abhängigkeiten, die eine konkrete Implementierung zwangsweise mit sich zieht, sind jene, die den Typ "schwergewichtig" machen, nicht die öffentliche Schnittstelle. Insofern macht es sehr wohl einen Unterschied ob es sich beim Typ um ein Interface oder eine Klasse handelt.
in C++ ja, da man dort immer das header benötigt! das I-prefix verwendet dort aber zum glück kaum einer, außer bei MS-sachen wie COM.
hier gehts aber viel mehr um java und .net.
und dort siehst du die abhängigkeiten nicht, sofern du nur den zwischencode und die dazugehörige doku hast (mehr braucht man auch nicht bei auslieferung einer komponente). somit es in java oder .net völlig egal ob es eine klasse oder interface ist. du siehst in beiden fällen nur die öffentlichen methoden.