Wie würden Sie diese Bedingung polymorphisieren?

8

Ich habe gerade das Google Clean Code-Video auf YouTube (siehe link , erster Artikel) zum Entfernen von if -Anweisungen von Ihrem YouTube-Konto abgeschlossen Code und verwenden stattdessen Polymorphismus.

Nachdem ich mir das Video angeschaut habe, habe ich mir einen Code angesehen, den ich geschrieben habe, bevor ich das Video angeschaut habe und einige Stellen bemerkt habe, an denen ich diese Methode anwenden konnte, hauptsächlich Orte, an denen die gleiche Logik viele Male implementiert wurde. Also ein Beispiel:

Ich habe einen Code wie diesen.

%Vor%

Was RunTableInfoCommand macht, ist nicht wirklich wichtig, aber die Hauptsache ist, dass ich viele Eigenschaften mit genau den gleichen if Statements habe. Die einzige Sache, die sich ändert, ist TableInfoEnum.

Ich habe mich gefragt, ob jemand mir helfen könnte, das so umzubauen, dass es immer noch dasselbe tut, aber ohne if -Anweisungen?

    
Nathan W 11.12.2008, 03:42
quelle

9 Antworten

8

Nur ein warnender Hinweis hier, nachdem Sie einige dieser (technisch korrekten) Antworten gesehen haben, nur eine If-Anweisung loszuwerden sollte nicht Ihr einziges Ziel sein, das Ziel sollte sein, Ihren Code erweiterbar, wartbar und einfach zu machen, wenn dies bedeutet loswerden einer if-Aussage, groß, aber es sollte kein Ziel an sich sein.

In dem Codebeispiel, das Sie angegeben haben, und ohne mehr über Ihre App zu wissen, und davon auszugehen, dass Sie nicht viel nach dem Test auf einen Nullwert erweitern werden, halte ich ein If (oder vielleicht sogar ein ternäres) für wartungsfreundlicher Lösung, um vollkommen ehrlich zu sein.

    
Tim Jarvis 11.12.2008, 04:08
quelle
4

Sie werden tatsächlich etwas wie das Strategie-Muster implementieren. Beginnen Sie mit der Definition einer Superklasse, lassen Sie sie AbstractTableInfoCommand aufrufen. Diese Klasse kann abstrakt sein, muss aber eine Methode namens runTableInfoCommand () angeben.

Sie können dann mehrere Unterklassen definieren, die jeweils die Methode runTableInfoCommand () implementieren. Ihre Klasse, die mit der Number-Eigenschaft, hat dann eine neue Eigenschaft vom Typ AbstractTableInfoCommand (lasst sie tableInfoCommand nennen), die in einer der konkreten Unterklassen von AbstractTableInfoCommand instanziiert wird.

Der Code lautet dann:

%Vor%

Sie können also einen NullTableInfoCommand und SomeOtherTableInfoCommand usw. erstellen. Der Vorteil ist, dass Sie, wenn Sie eine neue Bedingung für die Rückgabe eines tableinfocommand haben, eine neue Klasse hinzufügen, anstatt diesen Code zu bearbeiten.

Nachdem dies gesagt wurde, ist nicht unbedingt jede Situation für dieses Muster richtig. Es macht also mehr erweiterbaren Code, aber wenn Sie in einer Situation sind, die diese Erweiterbarkeit nicht erfordert, ist es übertrieben.

    
Vincent Ramdhanie 11.12.2008 03:55
quelle
1

Ich finde, dass Ihr Code vollkommen in Ordnung ist. Lesbar. Einfach. (Und ich hoffe, es funktioniert). Wenn dieser Codeblock n-mal wiederholt wird, müssen Sie die Duplizierung durch Anwendung der Extract-Methode entfernen.

Das Refactoring, das Sie angeben, soll wiederkehrende Switch-Fälle ersetzen. Nicht einfache if-Anweisungen wie in Ihrem Beispiel. Bedingtes durch Polymorphismus ersetzen . Erinnern Sie sich an die "einfachste Sache, die funktioniert". Dies bedeutet die minimale Anzahl von Klassen und Methoden, die erforderlich sind, um die Arbeit zu erledigen.

    
Gishu 11.12.2008 04:39
quelle
0

Ich würde vielleicht erwägen, das Abrufen des Rückgabewerts an eine andere Klasse zu übergeben, die zur Laufzeit injiziert werden könnte.

%Vor%

Das würde einen großen Teil des sich wiederholenden Codes behandeln und Ihre Abhängigkeit von der Quelle des Werts für eine Schnittstelle reduzieren.

Ich denke, Sie werden wahrscheinlich irgendwann eine if-Anweisung haben, da Sie immer noch entscheiden müssen, welche Version von RunTableInfoCommand Sie aufrufen möchten.

    
Andrew Kennan 11.12.2008 03:54
quelle
0

Ich nehme an, internTableName und InternalTableNumber sind eine Art Wert für die gleiche Sache. Warum sollte man es nicht innerhalb einer Klasse einpacken und eine Instanz dieser Klasse an this.RunTableInfoCommand like so übergeben:

%Vor%

Wenn Sie dann noch Polymorphismus verwenden möchten, können Sie dies in dieser Klasse tun, indem Sie zum Beispiel ein giveInternalTableIdentifier überladen, das die Zahl oder den Namen

zurückgibt

Der Code könnte dann so aussehen:

%Vor%

und der Code für die interneTabellenklasse ist trivial (mit: internalAbstractTableClass und zwei Klassen, die von ihr erben, wobei einer den Namen und der andere die Nummer angibt)

    
sven 11.12.2008 04:00
quelle
0

Ich würde es so umgestalten:

%Vor%

Liebe den ternären Operator.

    
ieure 11.12.2008 04:03
quelle
0

Ein Refactoring, das Polymorphismus beinhaltet, könnte in diesem Fall übertrieben sein (abhängig davon, welche anderen Vorteile Sie aus dem Polymorphismus herausholen könnten). In diesem Fall kann es sinnvoll sein, eine einfache Überladung hinzuzufügen, die die Logik enthält, deren RunTableInfoCommand() zum Aufruf gehört.

Da RunTableInfoCommand() , internalTableNumber und internalTableName alle der gleichen Klasse angehören, könnte es leicht sein, eine Überladung von RunTableInfoCommand() hinzuzufügen, die einfach einen TableInfoEnum Wert annimmt und macht die Logik herauszufinden, welche andere RunTableInfoCommand() Überladung aufgerufen werden muss:

%Vor%

Dann können die zahlreichen Aufruf-Sites, die die gleiche if Entscheidungslogik haben, zu:

reduziert werden %Vor%     
Michael Burr 11.12.2008 04:49
quelle
0

EDIT 2 Wie ich das Problem wirklich lösen würde.

Ich würde InternalTableNumber eine Eigenschaft machen, die faul geladen ist. Wenn es nicht verfügbar ist, würde ich es über den InternalTableName nachschlagen. Dann würde ich immer nur die InternalTableNumber-Eigenschaft für meine Methoden verwenden.

%Vor%

BEARBEITEN Polymorphismus verwenden ...

Angenommen, Ihre aktuelle Klasse heißt Foo, dann würde ich sie in zwei Klassen umwandeln, FooWithName und FooWithNumber. FooWithName wäre die Klasse, die Sie verwenden würden, wenn Sie den Tabellennamen haben, und FooWithNumber wäre die Klasse, die Sie verwenden möchten, wenn Sie die Tabellennummer haben. Ich würde dann jede Klasse mit einer Number-Methode schreiben - eigentlich werde ich auch eine Schnittstelle IFoo schreiben, die jede implementiert, damit sie austauschbar verwendet werden kann.

%Vor%

Sie würden es so verwenden:

%Vor%

Offensichtlich, wenn Sie nicht viele der if-then-else-Konstrukte in Ihrer bestehenden Klasse haben, verbessert diese Lösung sie nicht wirklich. Diese Lösung erstellt IFoo mit Polymorphie und verwendet dann nur die Interface-Methoden, ohne sich um die Implementierung zu kümmern. Dies könnte leicht erweitert werden, um eine allgemeine Implementierung von RunTableCommand (int) in einer abstrakten Klasse zu erben, die IFoo erbt und die Basisklasse für FooWithNum und FooWithName ist.

    
tvanfosson 11.12.2008 04:02
quelle
0

Wie würde ich diese speziellen if-Anweisungen umwandeln, um Polymorphie zu verwenden?

Nun ... ich würde nicht. Sie brauchen keinen Polymorphismus, um die if-Anweisungen zu eliminieren.

Beachten Sie, dass die if-Anweisungen nicht "schlecht" sind, die if-Anweisungen werden durch die Repräsentationswahl wo

verursacht %Vor%

Diese Verknüpfung impliziert eine fehlende Klasse , dh es wäre sinnvoller, eine InternalTable-Klasse zu haben, die internalTableName und internalTablenumber besitzt, da diese beiden Werte durch die Nullprüfungsregel stark verknüpft sind.

  • Diese neue Klasse könnte eine TableNumber-Eigenschaft bereitstellen, die die internalTableNumber == Nullprüfung
  • durchgeführt hat
  • und der RunTableInfoCommand könnte eine InternalTable-Instanz als Parameter verwenden (muss aber nicht, siehe nächstes Element).
  • Aber noch besser, die neue Klasse sollte eine Fassade für die RunTableInfoCommand-Methode (die vermutlich statisch ist) haben, die die Integer-Konvertierung durchgeführt hat.

Wenn angenommen wird, dass die InternalTable-Instanz den Namen iTable hat, würde der umsorgte Code der Sorge folgendermaßen aussehen:

%Vor%

Dies würde die Nullprüfung in der InternalTable-Klasse einkapseln. Das Ändern der ursprünglichen RunTableInfoCommand-Signatur ist optional.

Beachten Sie, dass dies nicht "die if-Anweisungen durch Polymorphismus ersetzt", aber es eliminiert die if-Anweisungen der konsumierenden Klasse durch Kapselung.

    
Steven A. Lowe 11.12.2008 06:18
quelle

Tags und Links