Namensprobleme: Sollte "ISomething" in "Something" umbenannt werden? [geschlossen]

68

In Onkel Bobs Kapitel über Namen in Clean Code wird empfohlen, Kodierungen in Namen zu vermeiden, vor allem in Bezug auf die ungarische Notation. Er erwähnt auch ausdrücklich das Entfernen des IPräfixes von den Schnittstellen, zeigt jedoch keine Beispiele dafür.

Nehmen wir folgendes an:

  • Die Verwendung der Schnittstelle dient hauptsächlich dazu, Testbarkeit durch Abhängigkeitsinjektion zu erreichen
  • In vielen Fällen führt dies zu einer einzigen Schnittstelle mit einem einzigen Implementierer

Wie sollten diese beiden zum Beispiel heißen? Parserund ConcreteParser? Parserund ParserImplementation?

public interface IParser {
    string Parse(string content);
    string Parse(FileInfo path);
}

public class Parser : IParser {
     // Implementations
}

Oder sollte ich diesen Vorschlag in Einzelfällen wie diesen ignorieren?

Vinko Vrsalovic
quelle
30
Das macht es nicht weniger zu einer Religion. Sie müssen nach Gründen suchen, nicht nur nach jemandem, den X als Y bezeichnet.
Mike Dunlavey
35
@MikeDunlavey Und das ist der Grund für die Frage!
Vinko Vrsalovic
14
Wenn ein Code vorhanden ist (den Sie nicht neu schreiben werden), halten Sie sich an die Konvention, die er verwendet. Wenn Sie neuen Code verwenden, verwenden Sie den Code, mit dem die Mehrheit der Leute, die daran arbeiten werden, am glücklichsten ist / sind. Nur wenn dies nicht zutrifft, sollte es sich um eine philosophische Frage handeln.
TripeHound
9
Die Mehrheitsregel "@TripeHound" ist nicht immer die beste Option. Wenn es Gründe gibt, aus denen manche Dinge besser sind als andere, kann eine einzelne Person den Rest des Teams davon überzeugen, auf der Grundlage dieser Gründe einen Fall zu erörtern. Nur blind der Mehrheit zu unterwerfen, ohne die Dinge zu bewerten, führt zur Stagnation. Ich sehe aus den Antworten, dass es für diesen konkreten Fall keinen guten Grund gibt, das Ist zu entfernen, aber das macht es nicht ungültig, überhaupt gefragt zu haben.
Vinko Vrsalovic
35
"Onkel Bobs" Buch konzentriert sich auf Java, nicht auf C #. Die meisten Paradigmen sind mit C # identisch, einige Namenskonventionen unterscheiden sich jedoch (siehe auch Funktionsnamen von lowerCamelCase in Java). Verwenden Sie beim Schreiben in C # die C # -Benennungskonventionen. Befolgen Sie jedoch den Hauptpunkt seines Kapitels über die Benennung: lesbare Namen, die die Bedeutung des Gegenstands wiedergeben!
Bernhard Hiller

Antworten:

191

Während viele, einschließlich "Onkel Bob", raten, nicht Ials Präfix für Schnittstellen zu verwenden, ist dies bei C # eine weit verbreitete Tradition. Im Allgemeinen sollte es vermieden werden. Wenn Sie jedoch C # schreiben, sollten Sie die Konventionen dieser Sprache befolgen und verwenden. Wenn Sie dies nicht tun, kommt es zu großer Verwirrung mit anderen mit C # vertrauten Personen, die versuchen, Ihren Code zu lesen.

David Arno
quelle
Kommentare sind nicht für längere Diskussionen gedacht. Diese Unterhaltung wurde in den Chat verschoben .
maple_shaft
9
Sie geben keine Grundlage für "Im Allgemeinen sollte es vermieden werden". In Java sollte ich vermieden werden. In C # sollte es umarmt werden. Andere Sprachen folgen ihren eigenen Konventionen.
Grund
4
Das Prinzip "allgemein" ist einfach: Ein Client sollte das Recht haben, nicht einmal zu wissen, ob es sich um eine Schnittstelle oder eine Implementierung handelt. Beide Sprachen haben das falsch verstanden. C # hat die Namenskonvention falsch verstanden. Java hat den falschen Bytecode erhalten. Wenn ich eine Implementierung auf eine Schnittstelle mit demselben Namen in Java umstelle, muss ich alle Clients neu kompilieren, obwohl sich der Name und die Methoden nicht geändert haben. Es ist kein "Wählen Sie Ihr Gift". Wir haben es einfach falsch gemacht. Bitte lernen Sie daraus, wenn Sie eine neue Sprache erstellen.
candied_orange
39

Die Schnittstelle ist das wichtige logische Konzept, daher sollte die Schnittstelle den generischen Namen tragen. Also hätte ich lieber

interface Something
class DefaultSomething : Something
class MockSomething : Something

als

interface ISomething
class Something : ISomething
class MockSomething : ISomething

Letzteres hat mehrere Probleme:

  1. Etwas ist nur eine Implementierung von ISomething, aber es ist die mit dem generischen Namen, als ob es etwas Besonderes wäre.
  2. MockSomething scheint von Something abzuleiten, implementiert jedoch ISomething. Vielleicht sollte es MockISomething heißen, aber das habe ich in freier Wildbahn noch nie gesehen.
  3. Refactoring ist schwieriger. Wenn Something jetzt eine Klasse ist und Sie erst später herausfinden, dass Sie eine Schnittstelle einführen müssen, sollte diese Schnittstelle den gleichen Namen haben, da für Clients transparent sein sollte, ob der Typ eine konkrete Klasse, eine abstrakte Klasse oder eine Schnittstelle ist . ISomething bricht das.
Wallenborn
quelle
59
Warum sollten Sie nicht den etablierten Standard von C # befolgen? Welchen Nutzen bringt dies, der die Kosten für die Verwirrung und Irritation jedes C # -Programmierers übersteigt, der Ihnen folgt?
Robert Harvey
6
@wallenborn Das ist in Ordnung, aber realistisch gesehen haben Sie oft nur eine legitime Implementierung einer Schnittstelle, da es üblich ist, Schnittstellen für die Spottbarkeit in Komponententests zu verwenden. Ich will nicht setzen Defaultoder Realoder Implin so viele meiner Klassennamen
Ben Aaronson
4
Ich stimme Ihnen zu, aber wenn Sie auf dieser Straße unterwegs sind, müssen Sie gegen jeden Linter kämpfen, der jemals für C # hergestellt wurde.
RubberDuck
3
Ich sehe kein Problem darin, eine instanziierbare Klasse mit demselben Namen wie eine Schnittstelle zu haben, wenn die überwiegende Mehrheit der Instanzen, die die Schnittstelle implementieren, diese Klasse sein wird. Zum Beispiel benötigt eine Menge Code eine unkomplizierte allgemeine Implementierung, IList<T>und es ist ihm egal, wie sie intern gespeichert wird. Die Möglichkeit, nur ein wenig von dem Izu lernen und einen verwendbaren Klassennamen zu haben, scheint besser zu sein, als magisch zu wissen (wie in Java), welchen Code eine gewöhnliche Implementierung verwenden List<T>soll ArrayList<T>.
Supercat
2
@ArtB Einige Gründe. Erstens gibt es keine Sprache, in der die Konvention eine nette Kurzbezeichnung für die Klasse darstellt CFoo : Foo. Diese Option ist also nicht wirklich verfügbar. Zwei, erhalten Sie eine seltsame Inkonsistenz dann weil einige Klassen den Marker haben würden und andere nicht, je nachdem , ob es vielleicht andere Implementierungen des gleichen Schnittstelle sein. CFoo : Fooaber SqlStore : Store. Das ist ein Problem, mit dem ich zu tun habe Impl, das im Wesentlichen nur ein hässlicherer Marker ist. Vielleicht, wenn es eine Sprache mit der Konvention gab, immer ein C(oder was auch immer) hinzuzufügen , könnte das besser sein alsI
Ben Aaronson
27

Hier geht es nicht nur um Namenskonventionen. C # unterstützt keine Mehrfachvererbung, daher bietet diese traditionelle Verwendung der ungarischen Notation einen kleinen, wenn auch nützlichen Vorteil, wenn Sie von einer Basisklasse erben und eine oder mehrere Schnittstellen implementieren. Also das...

class Foo : BarB, IBarA
{
    // Better...
}

... ist dem vorzuziehen ...

class Foo : BarB, BarA
{
    // Dafuq?
}

IMO

Robbie Dee
quelle
7
Es ist erwähnenswert, dass Java ordentlich dieses Problem vermeidet durch verschiedene Schlüsselwörter für Klassenvererbung und Interface - Implementierung verwendet wird , dh inheritsvs implements.
Konrad Rudolph
6
@KonradRudolph meinst du extends.
OrangeDog
2
@Andy Der Mehrwert ist, dass wir die Ungarische Notation vermeiden und dennoch die Klarheit bewahren können, die in dieser Antwort angepriesen wird.
Konrad Rudolph
2
Es sollte wirklich keine Verwirrung geben; Wenn Sie eine Klasse erben, MUSS sie an erster Stelle in der Liste stehen, bevor die Liste der implementierten Schnittstellen angezeigt wird. Ich bin mir ziemlich sicher, dass dies vom Compiler erzwungen wird.
Andy
1
@Andy ... Wenn Sie eine Klasse erben, MUSS sie an erster Stelle in der Liste stehen. Das ist großartig, aber ohne das Präfix würden Sie nicht wissen, ob Sie mit ein paar Schnittstellen oder einer Basisklasse und einer Schnittstelle zu tun haben ...
Robbie Dee
15

Nein nein Nein.

Namenskonventionen sind keine Funktion Ihres Onkel Bob-Fandoms. Sie sind keine Funktion der Sprache, c # oder auf andere Weise.

Sie sind eine Funktion Ihrer Codebasis. In viel geringerem Umfang Ihr Geschäft. Mit anderen Worten, der erste in der Codebasis setzt den Standard.

Nur dann können Sie sich entscheiden. Danach einfach konsequent sein. Wenn jemand anfängt inkonsistent zu sein, nimm seine Nerf-Waffe weg und lass sie die Dokumentation aktualisieren, bis sie Buße tun.

Wenn ich beim Lesen einer neuen Codebasis kein IPräfix sehe, ist das in Ordnung, unabhängig von der Sprache. Wenn ich auf jeder Schnittstelle eine sehe, geht es mir gut. Wenn ich manchmal einen sehe, wird jemand dafür bezahlen.

Wenn Sie sich in dem Kontext befinden, in dem Sie diesen Präzedenzfall für Ihre Codebasis festgelegt haben, sollten Sie Folgendes berücksichtigen:

Als Kundenklasse behalte ich mir das Recht vor, das, womit ich spreche, nicht gleichgültig zu machen. Ich brauche nur einen Namen und eine Liste von Dingen, die ich gegen diesen Namen anrufen kann. Diese dürfen sich nicht ändern, wenn ich es nicht sage. Ich besitze diesen Teil. Was ich spreche, Schnittstelle oder nicht, ist nicht meine Abteilung.

Wenn Sie sich Iin diesen Namen schleichen , ist es dem Kunden egal. Ist dies nicht Ider Fall, ist es dem Kunden egal. Womit es sich unterhält, könnte konkret sein. Es könnte nicht sein. Da es so oder so nicht newdarauf ankommt, macht es keinen Unterschied. Als Kunde weiß ich es nicht. Ich will es nicht wissen.

Als Code-Affe, der sich diesen Code ansieht, ist dies vielleicht sogar in Java wichtig. Wenn ich eine Implementierung in eine Schnittstelle ändern muss, kann ich das schließlich tun, ohne es dem Client mitzuteilen. Wenn es keine ITradition gibt, werde ich sie vielleicht nicht einmal umbenennen. Das könnte ein Problem sein, denn jetzt müssen wir den Client neu kompilieren, auch wenn es der Quelle egal ist, was die Binärdatei tut. Etwas, das leicht zu übersehen ist, wenn Sie den Namen nie geändert haben.

Vielleicht ist das für Sie kein Problem. Vielleicht nicht. Wenn ja, ist das ein guter Grund, sich darum zu kümmern. Aber aus Liebe zu Tischspielzeug sollten wir das nicht einfach blind machen, denn es ist die Art und Weise, wie es in irgendeiner Sprache gemacht wird. Entweder hast du einen verdammt guten Grund oder es ist mir egal.

Es geht nicht darum, für immer damit zu leben. Es geht darum, mich nicht über die Codebasis zu bescheißen, die nicht Ihrer speziellen Mentalität entspricht, es sei denn, Sie sind bereit, das Problem überall zu beheben. Wenn Sie keinen guten Grund haben, den Weg des geringsten Widerstands gegen Gleichförmigkeit nicht zu beschreiten, kommen Sie nicht zu mir und predigen Konformität. Ich habe besseres zu tun.

kandierte_orange
quelle
6
Konsistenz ist der Schlüssel, aber in einer statisch getippten Sprache und mit modernen Refactoring-Tools ist es ziemlich einfach und sicher, Namen zu ändern. Wenn also der erste Entwickler eine schlechte Wahl bei der Benennung getroffen hat, müssen Sie nicht ewig damit leben. Sie können die Benennung jedoch in Ihrer eigenen Codebasis ändern, jedoch nicht in den Framework- oder Drittanbieter-Bibliotheken. Da das I-Präfix (wie es ist oder nicht) eine in der gesamten .net-Welt etablierte Konvention ist, ist es besser, der Konvention zu folgen, als sie nicht zu befolgen.
JacquesB
Wenn Sie C # verwenden, werden Sie diese Is sehen. Wenn Ihr Code sie verwendet, sehen Sie sie überall. Wenn Ihr Code sie nicht verwendet, sehen Sie sie im Framework-Code, was genau zu der Mischung führt, die Sie nicht wollen.
Sebastian Redl
8

Es gibt einen winzigen Unterschied zwischen Java und C #, der hier relevant ist. In Java ist standardmäßig jedes Mitglied virtuell. In C # ist jedes Mitglied standardmäßig versiegelt - mit Ausnahme der Mitglieder der Benutzeroberfläche.

Die damit verbundenen Annahmen beeinflussen die Richtlinie - in Java sollte jeder öffentliche Typ gemäß dem Substitutionsprinzip von Liskov als nicht endgültig angesehen werden [1]. Wenn Sie nur eine Implementierung haben, geben Sie der Klasse einen Namen Parser. Wenn Sie feststellen, dass Sie mehrere Implementierungen benötigen, ändern Sie die Klasse einfach in eine Schnittstelle mit demselben Namen und benennen die konkrete Implementierung in eine beschreibende Implementierung um.

In C # ist die Hauptannahme, dass, wenn Sie eine Klasse erhalten (Name beginnt nicht mit I), dies die gewünschte Klasse ist. Wohlgemerkt, dies ist bei weitem nicht 100% genau - ein typisches Gegenbeispiel wären Klassen wie Stream(die eigentlich eine Schnittstelle oder ein paar Schnittstellen sein sollten), und jeder hat seine eigenen Richtlinien und Hintergründe aus anderen Sprachen. Es gibt auch andere Ausnahmen wie das häufig verwendete BaseSuffix für eine abstrakte Klasse - genau wie bei einer Schnittstelle wissen Sie, dass der Typ polymorph sein soll.

Es gibt auch eine nette Usability-Funktion, wenn Sie den Namen ohne I-Präfix für Funktionen belassen, die sich auf diese Schnittstelle beziehen, ohne die Schnittstelle zu einer abstrakten Klasse machen zu müssen (was aufgrund der fehlenden Klassenmehrfachvererbung in C # schaden würde). Dies wurde von LINQ, das IEnumerable<T>als Schnittstelle verwendet wird, und Enumerableals Repository von Methoden, die für diese Schnittstelle gelten, populär gemacht . Dies ist in Java nicht erforderlich, wo Schnittstellen auch Methodenimplementierungen enthalten können.

Letztendlich ist das IPräfix in der C # -Welt und in der .NET-Welt weit verbreitet (da der weitaus größte Teil des .NET-Codes in C # geschrieben ist, ist es sinnvoll, die C # -Richtlinien für die meisten öffentlichen Schnittstellen zu befolgen). Das bedeutet, dass Sie mit ziemlicher Sicherheit mit Bibliotheken und Code arbeiten werden, die dieser Notation folgen, und es ist sinnvoll, die Tradition zu übernehmen, um unnötige Verwirrung zu vermeiden - es ist nicht so, als würde das Weglassen des Präfixes Ihren Code verbessern :)

Ich gehe davon aus, dass Onkel Bobs Argumentation ungefähr so ​​war:

IBananaist der abstrakte Begriff der Banane. Wenn es eine implementierende Klasse geben kann, die keinen besseren Namen als hat Banana, ist die Abstraktion völlig bedeutungslos, und Sie sollten die Schnittstelle löschen und einfach eine Klasse verwenden. Wenn es einen besseren Namen gibt (etwa LongBananaoder AppleBanana), gibt es keinen Grund, ihn nicht Bananaals Namen für die Schnittstelle zu verwenden. Daher Ibedeutet die Verwendung des Präfixes, dass Sie eine nutzlose Abstraktion haben, wodurch der Code ohne Nutzen schwerer zu verstehen ist. Und da Sie beim strengen OOP immer Code gegen Schnittstellen verwenden, ist der einzige Ort, an dem Sie das IPräfix für einen Typ nicht sehen würden, ein Konstruktor - ziemlich sinnloses Rauschen.

Wenn Sie dies auf Ihre Beispielschnittstelle anwenden IParser, können Sie deutlich erkennen, dass sich die Abstraktion vollständig im "bedeutungslosen" Bereich befindet. Entweder es ist etwas Bestimmtes über eine konkrete Implementierung eines Parsers ( zum Beispiel JsonParser, XmlParser, ...), oder sollten Sie nur eine Klasse. Es gibt keine "Standardimplementierung" (obwohl dies in einigen Umgebungen tatsächlich Sinn macht, insbesondere COM), entweder gibt es eine bestimmte Implementierung, oder Sie möchten eine abstrakte Klasse oder Erweiterungsmethoden für die "Standardeinstellungen". IBehalten Sie es jedoch in C # bei, es sei denn, Ihre Codebasis lässt das Präfix bereits weg. Machen Sie sich einfach jedes Mal eine mentale Notiz, wenn Sie Code wie sehen class Something: ISomething- das bedeutet, dass jemand nicht sehr gut darin ist, YAGNI zu folgen und vernünftige Abstraktionen zu erstellen .

[1] - Technisch gesehen wird dies in Liskovs Artikel nicht speziell erwähnt, aber es ist eine der Grundlagen des ursprünglichen OOP-Artikels und in meiner Lektüre von Liskov hat sie dies nicht in Frage gestellt. In einer weniger strengen Interpretation (die von den meisten OOP-Sprachen verwendet wird) bedeutet dies, dass jeder Code, der einen öffentlichen Typ verwendet, der ersetzt werden soll (dh nicht endgültig / versiegelt), mit jeder konformen Implementierung dieses Typs funktionieren muss.

Luaan
quelle
3
Nitpick: LSP sagt nicht, dass jeder Typ nicht endgültig sein sollte. Es heißt nur, dass Konsumenten für Typen, die nicht endgültig sind, in der Lage sein müssen, Unterklassen transparent zu verwenden. - Und natürlich hat Java auch endgültige Typen.
Konrad Rudolph
@KonradRudolph Ich habe dazu eine Fußnote hinzugefügt; Danke für das Feedback :)
Luaan
4

Wie sollten diese beiden zum Beispiel heißen? Parser und ConcreteParser? Parser und ParserImplementation?

In einer idealen Welt sollten Sie Ihrem Namen keine Abkürzung ("I ...") voranstellen, sondern den Namen einfach ein Konzept ausdrücken lassen.

Ich habe irgendwo gelesen (und kann es nicht als Quelle angeben), dass diese ISomething-Konvention Sie dazu bringt, ein "IDollar" -Konzept zu definieren, wenn Sie eine "Dollar" -Klasse benötigen, aber die richtige Lösung wäre ein Konzept, das einfach "Währung" genannt wird.

Mit anderen Worten, die Konvention gibt der Schwierigkeit, Dinge zu benennen, ein leichtes Ende und das leichte Ende ist auf subtile Weise falsch .


In der realen Welt müssen die Clients Ihres Codes (die möglicherweise nur "Sie von der Zukunft" sind) in der Lage sein, ihn später zu lesen und sich so schnell (oder mit so wenig Aufwand) wie möglich damit vertraut zu machen (geben Sie die Clients von deinem Code, was sie erwarten zu bekommen).

Die ISomething-Konvention führt Cruft / Bad Names ein. Das heißt, die Cruft ist keine echte Cruft *), es sei denn, die Konventionen und Praktiken, die beim Schreiben des Codes verwendet werden, sind nicht mehr aktuell. Wenn in der Konvention "use ISomething" steht, ist es am besten, sie zu verwenden, um sich anderen Entwicklern anzupassen (und besser zu arbeiten).


*) Ich kann mit der Aussage davonkommen, dass "cruft" sowieso kein genaues Konzept ist :)

utnapistim
quelle
2

Wie in den anderen Antworten erwähnt, ist das Präfixieren Ihrer Schnittstellennamen ITeil der Codierungsrichtlinien für .NET Framework. Da in C # und VB.NET mit konkreten Klassen häufiger interagiert wird als mit generischen Schnittstellen, sind sie in Namensschemata erstklassig und sollten daher die einfachsten Namen haben - daher IParserfür die Schnittstelle und Parserfür die Standardimplementierung.

Bei Java und ähnlichen Sprachen, bei denen Schnittstellen anstelle konkreter Klassen bevorzugt werden, hat Onkel Bob jedoch Recht, da die Ientfernt werden sollten und die Schnittstellen die einfachsten Namen haben sollten - zum Beispiel Parserfür Ihre Parser-Schnittstelle. Anstelle eines rollenbasierten Namens ParserDefaultsollte die Klasse einen Namen haben, der beschreibt, wie der Parser implementiert wird :

public interface Parser{
}

public class RegexParser implements Parser {
    // parses using regular expressions
}

public class RecursiveParser implements Parser {
    // parses using a recursive call structure
}

public class MockParser implements Parser {
    // BSes the parsing methods so you can get your tests working
}

Dies ist zum Beispiel, wie Set<T>, HashSet<T>und TreeSet<T>sind benannt.

Der Hansinator
quelle
5
Schnittstellen werden auch in C # bevorzugt. Wer hat dir gesagt, dass es vorgezogen wird, Betontypen in Dotnet zu verwenden?
RubberDuck
@RubberDuck Es ist in einigen der Annahmen verborgen, die die Sprache Ihnen auferlegt. ZB die Tatsache, dass Mitglieder sealedstandardmäßig sind und Sie sie explizit festlegen müssen virtual. Virtuell zu sein ist der Spezialfall in C #. Da sich der empfohlene Ansatz zum Schreiben von Code im Laufe der Jahre geändert hat, mussten viele Relikte der Vergangenheit aus Kompatibilitätsgründen erhalten bleiben :) Der entscheidende Punkt ist, dass ISie wissen, dass eine Schnittstelle in C # (die mit beginnt ) eine vollständige Schnittstelle ist abstrakter Typ; Wenn Sie eine Nicht-Schnittstelle erhalten, ist die typische Annahme, dass dies der Typ ist, den Sie wollen, LSP, verdammt.
Luaan
1
Mitglieder sind standardmäßig versiegelt , so dass wir explizit über das, was Erben @Luaan über reiten. Zugegeben, es ist manchmal eine PITA, aber es hat nichts mit einer Vorliebe für konkrete Typen zu tun. Virtuell ist sicherlich kein Sonderfall in C #. Es hört sich so an, als hättest du das Pech gehabt, in einer C # -Codebasis zu arbeiten, die von Amateuren geschrieben wurde. Es tut mir leid, dass Sie diese Sprache erlebt haben. Es ist am besten, sich daran zu erinnern, dass der Entwickler nicht die Sprache ist und umgekehrt.
RubberDuck
@RubberDuck Hah, ich habe nie gesagt, dass es mir nicht gefällt. Ich bevorzuge es sehr, weil die meisten Leute Indirektion nicht verstehen . Auch unter Programmierern. Standardmäßig versiegelt ist meiner Meinung nach besser . Und als ich mit C # anfing, war jeder ein Amateur, einschließlich des .NET-Teams :) In "real OOP" sollte alles virtuell sein - jeder Typ sollte durch einen abgeleiteten Typ ersetzbar sein, der in der Lage sein sollte, jedes Verhalten außer Kraft zu setzen . Aber "real OOP" wurde für Spezialisten entwickelt, nicht für Leute, die vom Ersetzen von Glühbirnen zum Programmieren gewechselt sind, weil es weniger Arbeit für mehr Geld ist :)
Luaan
Nein ... Nein. So funktioniert "echtes OOP" überhaupt nicht. In Java sollten Sie sich die Zeit nehmen, Methoden zu versiegeln, die nicht außer Kraft gesetzt werden sollten, und es nicht wie im Wilden Westen belassen, wo jeder alles außer Kraft setzen kann. LSP bedeutet nicht, dass Sie alles außer Kraft setzen können, was Sie wollen. LSP bedeutet, dass Sie eine Klasse sicher durch eine andere ersetzen können. Smh
RubberDuck
-8

Sie haben Recht, dass diese I = Interface-Konvention die (neuen) Regeln verletzt

Früher haben Sie alles mit dem Typ intCounter boolFlag usw. vorangestellt.

Wenn Sie Dinge ohne Präfix benennen möchten, aber auch "ConcreteParser" vermeiden möchten, können Sie Namespaces verwenden

namespace myapp.Interfaces
{
    public interface Parser {...
}


namespace myapp.Parsers
{
    public class Parser : myapp.Interfaces.Parser {...
}
Ewan
quelle
11
Neu? alt? Warten Sie, ich dachte, beim Programmieren geht es mehr um Rationalität als um Hype. Oder war das früher?
3
Nein, es geht nur darum, Konventionen zu erfinden und zu bloggen, wie sie die Lesbarkeit verbessern
Ewan,
8
Ich glaube, Sie denken an die ungarische Notation, in der Sie Namen mit Typen vorangestellt haben. Aber es gab keine Zeit, in der Sie so etwas wie intCounteroder schreiben würden boolFlag. Das sind die falschen "Typen". Stattdessen schreiben Sie pszName(Zeiger auf eine NUL-terminierte Zeichenfolge, die einen Namen enthält), cchName(Anzahl der Zeichen in der Zeichenfolge "name"), xControl(x-Koordinate des Steuerelements), fVisible(Flag, das angibt, dass etwas sichtbar ist), pFile(Zeiger auf eine Datei), hWindow(Handle zu einem Fenster) und so weiter.
Cody Grey
2
Darin steckt noch viel Wert. Ein Compiler wird nicht den Fehler zu fangen , wenn Sie hinzufügen xControlzu cchName. Sie sind beide vom Typ int, haben aber eine sehr unterschiedliche Semantik. Die Präfixe machen diese Semantik für einen Menschen offensichtlich. Ein Zeiger auf eine mit NUL abgeschlossene Zeichenfolge sieht für einen Compiler genauso aus wie ein Zeiger auf eine Pascal-Zeichenfolge. Ebenso entstand das IPräfix für Interfaces in der Sprache C ++, in der Interfaces eigentlich nur Klassen sind (und in der Tat ist C, in dem es keine Klasse oder Schnittstelle auf Sprachebene gibt, alles nur eine Konvention).
Cody Grey
4
@CodyGray Joel Spolsky hat einen schönen Artikel geschrieben: Falschen Code falsch aussehen lassen über die ungarische Notation und die Art und Weise, wie er (falsch) verstanden wurde. Er ist einer ähnlichen Meinung: Das Präfix sollte ein übergeordneter Typ sein, nicht der Rohdatenspeichertyp. Er benutzt das Wort „Art“, erklärte, „Ich bin mit dem Wort Art absichtlich, da, weil Simonyi irrtümlich das Wort Typ in seinem Papier, und Generationen von Programmierern falsch verstanden , was er meinte.“
Joshua Taylor