Was ist der beste Weg zu ersetzen oder zu ersetzen, wenn ..else if..else Bäume in Programmen?
Diese Frage ist motiviert durch etwas, was ich in letzter Zeit begann zu sehen, ein bisschen zu oft, die if..else if..else
Struktur. Es ist zwar einfach und hat auch seinen nutzen, etwas über es sagt mir immer wieder, dass es könnte ersetzt werden, mit etwas, das mehr ist feinkörnig, elegant und einfach in der Regel einfacher zu halten up-to-date.
So genau wie möglich, dies ist, was ich meine:
if (i == 1) {
doOne();
} else if (i == 2) {
doTwo();
} else if (i == 3) {
doThree();
} else {
doNone();
}
Ich denken kann, sind zwei einfache Möglichkeiten, um zu umschreiben, entweder durch ternäre (was nur eine andere Schreibweise der gleichen Struktur):
(i == 1) ? doOne() :
(i == 2) ? doTwo() :
(i == 3) ? doThree() : doNone();
oder mit Karte (in Java, und ich denke in C#) oder Wörterbuch oder jede andere K/V Struktur wie dieser:
public interface IFunctor() {
void call();
}
public class OneFunctor implemets IFunctor() {
void call() {
ref.doOne();
}
}
/* etc. */
Map<Integer, IFunctor> methods = new HashMap<Integer, IFunctor>();
methods.put(1, new OneFunctor());
methods.put(2, new TwoFunctor());
methods.put(3, new ThreeFunctor());
/* .. */
(methods.get(i) != null) ? methods.get(i).call() : doNone();
In der Tat die Map-Methode, die oben ist, was ich am Ende tun die Letzte Zeit, aber jetzt ich kann nicht aufhören zu denken, dass es bessere alternativen im Allgemeinen für genau dieses Problem.
So, die anderen -und wahrscheinlich besser - Wege zu ersetzen, die if..else if..else draußen sind, und welches ist Ihr Favorit?
Ihre Gedanken unterhalb dieser Zeile!
Okay, hier sind Ihre Gedanken:
Erste, beliebteste Antwort war "switch" - Anweisung, etwa so:
switch (i) {
case 1: doOne(); break;
case 2: doTwo(); break;
case 3: doThree(); break;
default: doNone(); break;
}
Das funktioniert nur für Werte, die verwendet werden können in-Schalter, was zumindest in Java ist durchaus ein limitierender Faktor. Akzeptabel für einfache Fälle, obwohl, natürlich.
Den anderen und vielleicht etwas ausgefalleneren Art und Weise Sie scheinen zu sugges ist, es zu tun Polymorphismus. Die Youtube-Vorlesung verbunden, die von CMS ist eine hervorragende Uhr, gehen Sie sehen es hier: "The Clean Code Talks -- Vererbung, Polymorphismus, & - Prüfung" soweit ich das verstanden, würde dies übersetzen, so etwas wie dieses:
public interface Doer {
void do();
}
public class OneDoer implements Doer {
public void do() {
doOne();
}
}
/* etc. */
/* some method of dependency injection like Factory: */
public class DoerFactory() {
public static Doer getDoer(int i) {
switch (i) {
case 1: return new OneDoer();
case 2: return new TwoDoer();
case 3: return new ThreeDoer();
default: return new NoneDoer();
}
}
}
/* in actual code */
Doer operation = DoerFactory.getDoer(i);
operation.do();
Zwei interessante Punkte aus dem Google-talk:
- Null-Objekte, statt der Rückgabe von null-Werten (und bitte werfen Sie nur Runtime-Exceptions)
- Versuchen zu schreiben, ein kleines Projekt ohne wenn:s.
Darüber hinaus auch einen Beitrag erwähnenswert ist meiner Meinung nach CDR, seine perversen Gewohnheiten mit uns, und zwar nicht empfohlen, um zu verwenden, es ist einfach sehr interessant zu Lesen.
Danke an Euch alle für die Antworten (bisher), ich glaube ich habe etwas gelernt heute!
InformationsquelleAutor der Frage Esko | 2009-02-06
Du musst angemeldet sein, um einen Kommentar abzugeben.
Diese Konstrukte können oft ersetzt werden durch Polymorphismus. Dies wird Ihnen kürzer und weniger spröde code.
InformationsquelleAutor der Antwort Brian Rasmussen
Einer switch-Anweisung:
InformationsquelleAutor der Antwort Andrew Kennan
In Objekt-Orientierten Sprachen ist es üblich, verwenden Polymorphismus zu ersetzen, wenn Sie.
Mochte ich diese Google Clean Code Talk, deckt das Thema:
Die Clean Code Talks -- Vererbung, Polymorphismus, & Tests
InformationsquelleAutor der Antwort CMS
Es gibt zwei Teile auf diese Frage.
Wie Versand basierend auf einem Wert? Verwenden Sie eine switch-Anweisung. Sie zeigt Ihre Absicht, die meisten deutlich.
Wenn Versand basierend auf einem Wert? Nur an einer Stelle pro Wert: erstellen Sie eine polymorphe Objekt, das weiß, wie das erwartete Verhalten für den Wert.
InformationsquelleAutor der Antwort
Je nach der Art der Sache, die Sie if..else ' Ing, erstellen Sie eine Hierarchie von Objekten und Polymorphismus. Etwa so:
Dann in deinem code nur aufrufen, p->Foo() und das richtige wird passieren.
InformationsquelleAutor der Antwort Steve Rowe
Den Schalter Aussage natürlich viel schöner dann diese if 's und else' s.
InformationsquelleAutor der Antwort colithium
Außerhalb der switch-Anweisung verwenden, die schneller sein können, keine. If Else ist klar und leicht zu Lesen. anschauen müssen die Dinge in einer Karte verbirgt Dinge. Warum machen code schwerer zu Lesen?
InformationsquelleAutor der Antwort WolfmanDragon
Zusammengenommen muss ich sagen, dass es ist nicht viel falsch mit Ihrem if-Anweisung. Wie Einstein sagte: "Machen Sie es so einfach wie möglich-aber nicht einfacher".
InformationsquelleAutor der Antwort Rolf
Benutze ich kurzer hand einfach nur zum Spaß! Versuchen Sie nicht anyof diese, wenn code-Klarheit betrifft Sie mehr als die Anzahl der Zeichen eingegeben haben.
Fällen, in denen doX() gibt immer true zurück.
Natürlich ich versuche, dass die meisten void-Funktionen geben 1 zurück, einfach um sicherzustellen, dass diese kurzen Hände sind möglich.
Können Sie auch Zuordnungen.
Wie instad von writting
Schreiben
In den Fällen, wo nicht wissen, was die Funktion zurückgibt, fügen Sie einen ||1 🙂
Ich finde es immer noch schneller eingeben, als mit allen denjenigen, if-else und es erschreckt alle neuen noobs aus. Stellen Sie sich eine volle Seite der Anweisung, wie dies mit 5 Ebenen Einrücken.
"wenn" selten ist in einigen meiner codes und ich habe ihm den Namen "wenn-weniger Programmierung" 🙂
InformationsquelleAutor der Antwort CDR
In diesem einfachen Fall könnten Sie einen switch verwenden.
Sonst einer Tabelle-basierten Ansatz sieht gut aus, es wäre meine zweite Wahl, Wann immer die Bedingungen sind regelmäßig genug, um es zutreffend, vor allem, wenn die Zahl der Fälle ist groß.
Polymorphismus wäre eine option, wenn es nicht zu viele Fälle und die Bedingungen und Verhaltensweisen sind unregelmäßig.
InformationsquelleAutor der Antwort starblue
Das Beispiel in der Frage ist trivial genug sind, um mit einem einfachen Schalter. Das problem kommt, wenn die if-elses verschachtelt sind, immer tiefer und tiefer. Sie sind nicht mehr "eindeutig oder einfach zu Lesen ist," (wie jemand anderes argumentiert) und das hinzufügen von neuem code oder beheben von Fehlern in Ihnen wird immer schwieriger und härter, um sicher zu sein, weil Sie möglicherweise nicht am Ende, wo Sie erwartet, wenn die Logik ist Komplex.
Ich habe gesehen, das passiert sehr oft (Schalter verschachtelte 4 Ebenen tief und Hunderte von Zeilen lang--nicht mehr zu halten), vor allem im inneren der factory-Klassen, die versuchen, zu viel zu tun für zu viele nicht verwandten Arten.
Wenn die Werte, die Sie vergleichen, sind nicht bedeutungslos, ganze zahlen, sondern eine Art eindeutige id (z.B. Verwendung von enums als eines Armen Mannes Polymorphismus), dann möchten Sie die Verwendung von Klassen, um das problem zu lösen. Wenn Sie wirklich nur numerische Werte, dann würde ich eher verwenden, eigene Funktionen zu ersetzen, die den Inhalt des if-und else-Blöcken, und nicht das design eine Art künstliche Hierarchie der Klasse zu vertreten. Am Ende führen kann, messier-code als das original spaghetti.
InformationsquelleAutor der Antwort Michel
Verwenden Sie eine switch/case " - es ist sauberer :p
InformationsquelleAutor der Antwort fmsf
switch
Anweisung oder Klassen mit virtuellen Funktionen als ausgefallene Lösung. Oder ein array von Zeigern auf Funktionen. Es hängt alles davon ab, wie Komplex die Bedingungen sind, manchmal gibt es keine Möglichkeit, um diese wenn. Und erneut, die Schaffung Reihe von Klassen zu vermeiden, eine switch-Anweisung ist eindeutig falsch, der code sollte so einfach wie möglich (aber nicht einfacher)InformationsquelleAutor der Antwort vava
In OO-Paradigma, Sie könnte tun Sie es mit guten alten Polymorphismus. Zu groß if - else-Strukturen oder switch-Konstrukte sind manchmal als ein Geruch in den code.
InformationsquelleAutor der Antwort Nazgob
Die Map-Methode ist die beste, die es gibt. Es ermöglicht die Kapselung der Anweisungen und Pausen, die die Dinge ganz gut. Polymorphismus ergänzen können, aber die Ziele sind etwas anders. Es führt auch zu unnötigen Klasse Bäume.
Schalter haben den Nachteil, dass die fehlende break-Anweisungen und fallen durch, und wirklich ermutigen, nicht zu brechen das problem in kleinere Stücke.
Dass gesagt wird: Ein kleiner Baum von if..else ist in Ordnung (in der Tat, ich plädierte dafür, für die Tage über haben 3 wenn..elses statt mit Karte vor kurzem). Es ist, wenn Sie beginnen, mehr komplizierte Logik, dass es zu einem problem aufgrund der Wartbarkeit und Lesbarkeit.
InformationsquelleAutor der Antwort Richard Levasseur
In python würde ich den code schreiben als:
InformationsquelleAutor der Antwort too much php
Ich würde so weit gehen zu sagen, dass kein Programm jemals benutzen sonst. Wenn Sie tun, Sie sind ärger bringen. Sie sollten nie davon ausgehen, wenn es nicht ein X muss es eine Y. tests sollte der test für jeden individuell und scheitern, nach solchen tests.
InformationsquelleAutor der Antwort mP.
Betrachte ich diese if-elseif -... - Konstrukten, die als "keyword-Lärm". Es mag zwar klar sein, was es tut, es fehlt Prägnanz; ich halte Prägnanz als ein wichtiger Bestandteil der Lesbarkeit. Die meisten Sprachen bieten so etwas wie eine
switch
- Anweisung. Aufbau einer Karte ist ein Weg, um etwas ähnliches in Sprachen, die nicht über eine solche, aber es fühlt sich wie ein workaround, und es ist ein bisschen overhead (eine switch-Anweisung übersetzt, um einige einfache Operationen vergleichen und bedingten Sprüngen, aber eine Karte zuerst gebaut wird, im Speicher, die dann abgefragt, und dann erst das vergleichen und Sprung stattfindet).In Common Lisp gibt es zwei switch-Konstrukte gebaut, die
cond
undcase
.cond
ermöglicht es, beliebige Bedingungen, währendcase
nur tests für Gleichheit, aber ist übersichtlicher.Natürlich, Sie machen Ihre eigene
case
-wie makro für Ihre Bedürfnisse.In Perl, können Sie die
for
Anweisung, Optional mit einer beliebigen Bezeichnung (hier:SWITCH
):InformationsquelleAutor der Antwort Svante
Verwendung eines Ternären Operator!
Ternärer Operator(53Characters):
Wenn(108Characters):
Switch((SOGAR LÄNGER, ALS WENN!?!?)114Characters):
dies ist alles, was Sie brauchen! es ist nur eine Zeile und es ist Recht ordentlich, der Weg kürzer als Schalter und wenn!
InformationsquelleAutor der Antwort Qyther
Natürlich, diese Frage ist von der Sprache abhängig, aber ein switch-Anweisung kann eine bessere option sein, in vielen Fällen. Eine gute C-oder C++ - compiler in der Lage sein zum generieren eines Sprung-Tabelledie deutlich schneller für große Gruppen von Fällen.
InformationsquelleAutor der Antwort jasonmray
Wenn Sie wirklich müssen eine Reihe von if-tests und wollen verschiedene Dinge tun whenwver ein test wahr ist, würde ich empfehlen, eine while-Schleife mit nur ifs - keine sonst. Jeden falls hat ein test eine ruft eine Methode auf, dann bricht aus der Schleife. Nein sonst gibt es nichts Schlimmeres, als einen Haufen gestapelt if/else/if/else-etc.
InformationsquelleAutor der Antwort mP.