Wie vermeide ich allgemeine Namen für abstrakte Klassen?

10

Im Allgemeinen ist es gut, Wörter wie "handle" oder "process" als Teil von Routinennamen und Klassennamen zu vermeiden, es sei denn, Sie haben es mit (z. B.) Dateihandles oder (z. B.) Unix-Prozessen zu tun. Abstrakte Klassen wissen jedoch oft nicht wirklich, was sie mit etwas anderem anfangen sollen, als es beispielsweise zu verarbeiten. In meiner aktuellen Situation habe ich einen "EmailProcessor", der sich im Posteingang eines Benutzers anmeldet und Nachrichten von diesem verarbeitet. Es ist mir nicht wirklich klar, wie ich diesem einen genaueren Namen geben soll, obwohl ich bemerkt habe, dass die folgende Stilfrage auftritt:

  • Es ist besser, abgeleitete Klassen als Clients zu behandeln und die Basisklasse nach dem Teil der von ihr implementierten Funktionalität zu benennen. Gibt ihm mehr Bedeutung, verstößt aber gegen is-a. Zum Beispiel wäre EmailAcquirer ein vernünftiger Name, da er für die abgeleitete Klasse erworben wird, die abgeleitete Klasse jedoch für niemanden.
  • Oder einfach nur ein vager Name, denn wer weiß, was die abgeleiteten Klassen tun werden. "Prozessor" ist jedoch immer noch zu allgemein, da er viele relevante Vorgänge ausführt, z. B. das Anmelden und Verwenden von IMAP.

Ein Ausweg aus diesem Dilemma?

Das Problem ist offensichtlicher für abstrakte Methoden, bei denen Sie die Frage "Was macht das?" Nicht wirklich beantworten können. denn die Antwort lautet einfach "was auch immer der Kunde will".

Djechlin
quelle
Haben Sie eine Quelle (und einen Kontext) für diese "allgemeine" Behauptung? Außerdem eine zusätzliche Namensregel für die Liste - verschwenden Sie keine Zeit damit, nach einem perfekten Namen zu suchen, der wahrscheinlich nicht existiert. Wenn Sie Zweifel haben, geben Sie ihm den bestmöglichen Namen, fügen Sie eine längere Beschreibung als Kommentar hinzu, wo sie bei Bedarf definiert ist. Sie können sie jedoch später jederzeit umgestalten, wenn jemand Ihre Wahl nicht mag oder Ihnen plötzlich der perfekte Name einfällt, wenn Sie Ich mache etwas anderes.
Steve314
3
@ Steve314 - ja, Steve McConnell, Code Complete, 1. Ausgabe, Kapitel 4 oder 5 über Routinen. Ausführliche Diskussion über die Benennung in diesen Kapiteln. Wenn Sie keinen guten Namen haben, haben Sie wahrscheinlich keine gute Funktion.
Djechlin
Wenn Sie keinen guten Namen finden, scheint dies ein schlechtes Zeichen zu sein. IMO sollten Sie jedoch anhand der Funktion selbst wissen, ob die Funktion schlecht ist. Refactoring, nur weil die englische Sprache nicht speziell für Ihr Projekt entwickelt wurde, ist ein bisschen dumm. Nein, es ist kein alltägliches Problem, aber Sie haben bereits entschieden, dass Sie ein Problem haben.
Steve314
1
@ Steve314 Beim Programmieren geht es ausschließlich um das Verwalten von Komplexität. Wenn Ihr Gehirn kein Wort für etwas finden kann, besteht eine gute Chance, dass es die Komplexität nicht verwalten kann, wenn es beispielsweise verwendet werden muss größere Sätze oder als Teil größerer Systeme. Es ist eigentlich keine kühne Behauptung zu sagen, dass die Unfähigkeit, einen guten Namen zu finden, ein wichtiger Grund zur Besorgnis ist. Aber dies wird in McConnell ausführlich besprochen. Ich würde empfehlen, zumindest diese beiden Kapitel zu lesen, obwohl es sich lohnt, das gesamte Buch von vorne bis hinten zu lesen.
Djechlin
Den Ansprüchen in Code Complete sollte nicht unbedingt vertraut werden. Ich bin mir bewusst , der Bücher Ruf, aber ich bin auch bewusst diese . Außerdem habe ich die Komplexität seit Ewigkeiten perfekt gemanagt - natürlich passieren Fehler, aber wenn etwas schief geht, ist das Problem manchmal eine Funktion, die so einfach ist, dass sie offensichtlich nicht falsch sein kann, aber trotzdem ist .
Steve314

Antworten:

10

Das Problem ist nicht der Name, sondern dass Sie zu viel in eine Klasse stecken.

In Ihrer Beispielklasse sind einige Teile sehr konkret (wie die Mails erhalten werden). Andere Teile sind sehr abstrakt (was Sie mit den Mails machen werden).

Besser mit separaten Klassen als mit Vererbung.

Ich schlage vor:

  • ein abstrakter MessageIterator, der von einem POPMailBoxDownloader untergeordnet wird

  • Eine andere Klasse, die einen POPMailBoxDownloader besitzt und etwas mit den Nachrichten macht.

Kris Van Bael
quelle
Das klingt genau richtig. Es hört sich so an, als ob Sie etwas "processEvent" oder eine Klasse "MessageProcessor" nennen. Es besteht eine gute Chance, dass Sie über Komposition statt Ableitung entworfen haben. In diesem Fall ist es ein Kompromiss, da die Flexibilität als Betreuer nützlich sein kann, aber ein Kunde würde sich darüber ärgern, was jede Funktion genau tut (mehr als der Betreuer).
Djechlin
6

Wenn ich keinen guten Namen für eine Klasse finde, schreibe ich eine Inline-Codedokumentation für die Klasse. Es beschreibt den Zweck der Klasse in einem Duft. Normalerweise kann ich aus dieser Beschreibung einen guten Namen für die Klasse ableiten. Dies ist auch für abstrakte Klassen hilfreich.

Wenn die Beschreibung der Klasse "Anmeldet sich im Posteingang eines Benutzers und verarbeitet Nachrichten von diesem" lautet, würde ich "InboxProcessor" als Klassennamen vorschlagen. Wenn eine abgeleitete Klasse "Anmeldet sich im Posteingang eines Benutzers und verschiebt Spam-E-Mails in einen Spam-Ordner" als Beschreibung hat, würde ich "InboxSpamMover" als Namen wählen.

Ich sehe kein Problem bei der Verwendung von generischen Namen wie "Prozessor", wenn dies den generischen Zweck einer abstrakten Klasse widerspiegelt.

Wenn Sie Probleme haben, den Zweck einer Klasse in ein oder zwei Sätzen zu beschreiben, liegt möglicherweise ein Entwurfsproblem vor. Vielleicht macht die Klasse zu viel und verstößt gegen das Prinzip der Einzelverantwortung . Dies gilt auch für abstrakte Klassen.

Theo Lenndorff
quelle
2

Um Frank Zappa zu paraphrasieren, es ist, was es ist und sollte so genannt werden. Ihr Beispiel geht einfach nicht tief genug in die Art der Verarbeitung ein. Ist es ein EmailToTroubleTicketProcessor, ein EmailGrammarCorrectoroder ein EmailSpamDetector?

Das Problem ist offensichtlicher für abstrakte Methoden, bei denen Sie die Frage "Was macht das?" Nicht wirklich beantworten können. denn die Antwort lautet einfach "was auch immer der Kunde will".

Das ist nicht genau richtig; Die Frage, die Sie für etwas Abstraktes nicht beantworten können, lautet: " Wie macht es das, was es macht?" denn das ist implementierungsspezifisch. Wenn eine EmailSenderKlasse über eine DeliveryStatus deliver(Email e)Methode verfügt, gibt es einen impliziten Vertrag, wonach eine Implementierung eine E-Mail entgegennimmt, versucht, sie zuzustellen und einen Status über den Verlauf zurückzugeben. Es ist Ihnen egal, ob eine Verbindung zu einem SMTP-Server hergestellt oder ausgedruckt wird, um an eine Brieftaube gebunden zu werden, solange die Implementierung das tut, was versprochen wurde. Abstracts quantifizieren dieses Versprechen nur, damit eine Implementierung sagen kann: "Ja, das mache ich."

Blrfl
quelle
Was ist, wenn die Endfunktion in gewisser Weise terminal ist und die abstrakte Klasse sagt: "Und das hier, mach was du willst damit?" zB hat die Methode keinen Zugriff auf state, void return type, no-throw.
Djechlin
Es ist immer noch dasselbe. Selbst wenn Ihre Methode dies ist void doWhatYouDoWith(Email e), können Sie die Klasse dennoch als an bezeichnen EmailDisposer. Dies ist spezifisch genug, um zu sagen, was sie tut, aber allgemein genug, um festzustellen, wie die Implementierung erfolgt. Obwohl ich denke, dass @KrisVanBael es geschafft hat: Wenn Sie auf etwas so Zweideutiges zurückgegriffen haben, ist möglicherweise zu viel unter einem Dach.
Blrfl
0

Überlegen Sie, warum es schlecht ist, solche Wörter zu verwenden. Sind sie beschreibend? Welche Wörter gibt es, um die Klassen zu beschreiben ? EmailBaseClass? Könnte das aussagekräftiger sein als EmailManager oder ähnliches? Der Schlüssel ist, einen Einblick in die betreffende Klasse zu haben , also finden Sie die richtigen Verben oder Substantive. Behandle deinen Code wie Poesie.

zxcdw
quelle
"EmailBaseClass" wäre wie die Bezeichnung int age"ageInteger", nur noch schlimmer, da ich erwarten würde, daraus Klartext-E-Mails, MIME-E-Mails usw. abzuleiten. Keine Notwendigkeit zu beschreiben, was das Wort überhaupt vorausgeht abstract(dies ist Java). Haben Sie einen besonderen Einblick in den Basisteil dieser Klasse? Und mehr Einsicht löst immer noch nicht das Problem, etwas zu benennen, das eine Is-a-Beziehung kreuzen wird. Ich kann entweder etwas zu Vages oder zu Allgemeines haben. Ich sehe keinen Ausweg, es sei denn, ich hätte es getan mehr Einblick in mehr Einblick.
Djechlin
@djechlin - es gibt seltene Fälle, in denen ageIntegeroder so etwas tatsächlich angemessen ist. Die ungarische Notation ist eine abgekürzte Version aus einem Kontext, in dem viel passiert ist. Sicherlich gibt es Zeiten, in denen Sie etwas in der Art und Weise ageNumericund ageStringim gleichen Umfang benötigen , wobei die Angabe des Typs im Namen die einfachste und klarste Methode zur Unterscheidung ist.
Steve314
@djechlin ich persönlich es am einfachsten zu Arbeit mit dem Code findet, kann ich nur peek ein Verständnis gewinnt an zu. Das heißt, Namen sagen mir, womit ich arbeite. Sie müssen nicht wissen, ob systemControlleres sich um eine abstrakte Basisklasse oder ein Blatt in einer großen Hierarchie handelt. Natürlich kann dies mit einer IDE behoben werden (wie es bei den meisten Java-Entwicklungen der Fall ist?), Die den Benutzer sofort über den Inhalt und die Struktur der Klasse informieren kann, sodass tatsächlich aufschlussreiche Namen nicht in ähnlicher Weise gerechtfertigt werden können.
zxcdw