| 

.NET C# Java Javascript Exception

3
Ich lese aktuell das Buch "Clean code" in dem unter anderem die SOLID-Prinzipien vermittelt werden. Da ich noch nicht so der erfahrende Programmierer bin, wollte ich meine Aussage die ich einem Kollegen genannt habe bestätigen lassen.

Es ging um eine Case-switch Anweisung und dass er sie "liebt". (wahrscheinlich weil if else sehr mühsam wäre)
Ich entgegnete hingegen, dass case-switch eigentlich immer gegen das OpenClosed Prinzip verstoßen und dass er es über Dependency Injection lösen könnte, weil er dann das Open/Closed Prinzip respektiert.

Falls meine Annahme richtig ist, ergänzen die zwei Prinzipien sich sehr gut.

1. Lag ich mit meiner Aussage richtig?

2. Gibt es weitere Möglichkeiten geschickt case-switch Strukturen zu vermeiden?
07.08.2009
Tribal123 185 2 5
1
Kannst du kurz erklären worauf deine Meinung beruht damit wir das Verständnisproblem beheben können.
gfoidl 07.08.2009
6 Antworten
6
Case-switch sowie if-else haben weder mit "Open Closed" noch mit "Depency Injection" etwas am Hut denn es sind Befehle für die bedingte Ausführung von Code.

Open Closed ist ein Prinzip das besagt dass Klassen offen für Erweiterungen und geschlossen für Veränderungen sein sollen. Dies bezieht lediglich auf das API der Klasse - also wie die Klasse von außen aussieht*. Konkreter gesagt heißt das dass alle öffentlichen Member sich nicht ändern sollen aber die Klasse durch Vererbung erweitert werden darf.
* das Prinzip kann auch auf Member angewandt werden

Depency Injection ist wiederum ganz was anderes und ist ein Entwurfsmuster das vorgesehen ist um Abhängigkeiten zwischen Objekten zu minimieren. Es wird in der Objekterstellung verwendet und kann als Evolution einer Fabrikmethode verstanden werden. Eine anschauliches Beispiel zeigt der Wiki-Artikel darüber. Konkret geht es in diesem Beispiel darum die Abhängigkeit von 'Car' und 'Engine' zu minimieren indem dem 'Car' die 'Engine' von außen mitgeteilt (injiziert) wird -> daher die Bezeichnung Depency injection.

Es hat also keiner der Begriffe etwas mit den Bedingungs-Anweisungen zu tun.
07.08.2009
gfoidl 9,4k 3 5
1
Ja ich glaube wirklich ich habe etwas falsch verstanden. Vielen Dank, dein Post verschafft mir Klarheit :)
Tribal123 09.08.2009
1
Dann kannst du bitte die Antwort als akzeptiert kennzeichnen.
gfoidl 09.08.2009
1
Sorry, war keine Absicht :)
Tribal123 09.08.2009
1
Die Antwort, das hätte nichts miteinander zu tun, halte ich für schlichtweg falsch (siehe die Antwort von oopexpert und auch meine Antwort für die Begründung).
Golo Roden 05.05.2011
2
Sowohl Dependenciy Injection als auch switch-case-Anweisungen sind mit die schlechtesten Methoden, die jemals in OO-Sprachen eingebracht wurden.

Dependency Injection fordert Bean Konventionen. Beans verstoßen gegen das Geheimnisprinzip. Dependency Injection verstößt somit gegen das Geheimnisprinzip. Beans sollten sowieso vermieden werden (http://www.javapractices.com/topic/TopicAction.do?Id=84)

Switch-Case-Anweisungen verstoßen meistens gegen das Open-Closed-Prinzip und zwar aus folgendem Gründen: Meistens gibt es mehrere Stellen im Code, die ähnlich Abfragen machen, aber unterschiedliche Abläufe steuern. Kommt nun ein neuer Fall hinzu, muss man mehr als eine Code-Stelle anpassen, nämlich jede Stelle, an der die Abläufe anhand des Prädikats gesteuert werden. If- und Switch-Case-Anweisungen besitzen immer einen Default-Fall, der explizit betrachtet werden muss. Strukturell bedeutet Default "alles andere, was ich noch nicht behandelt habe" und für zu einem schlechten, faulen Stil. Die Wohldefiniertheit bleibt auf der Strecke. In OO werden Switch-Case-Anweisunge durch Klassen-Strukturen substituiert. Klassifiziere die Aufgaben einer Anwendung angemessen, dann brauch man wesentlich weniger switch-case-Anweisungen
05.05.2011
oopexpert 455 1 8
valide argumentation, verstehe das negativrating nicht. immer diese glaubenskriege ;)
CRegenschein 05.05.2011
1
Also was switch-case, OCP und OOP angeht, gebe ich Dir vollkommen Recht.

Allerdings habe ich nicht verstanden, was DI mit Beans zu tun hat - kannst Du mir das eventuell mal erklären?
Golo Roden 05.05.2011
Zu den Glaubenskriegen: Es gibt Dinge, die kann man so oder so machen. Man kann darüber diskutieren, ob ein Prinzip, gegen das man verstößt, schwerer wiegt als ein anderes. Das ist stark situativ. Aber DASS man dagegen verstößt ist eine Tatsache.

Zu Dependency Injection: Dependency Injection fordert den Bean-Charakter einer Klasse, um dynamisch zur Laufzeit die Assoziation aufbauen zu können. Und Beans verstoßen per Definition schon gegen das Geheimnisprinzip, weil sie setter und getter für ihre Attribute bereitstellen. Die Indirektion ist damit so viel Wert wie ein public Attribut.
oopexpert 06.05.2011
Zusatz Dependency Injection: Für Module und schwergewichtige Komponenten überwiegt das Prinzip der losen Kopplung. Dafür kann DI einen guten Beitrag leisten.

Beim Einsatz in Fachklassen (Business Objects, Domain objects, usw.) wiegt die Konistenz stärker als die lose Kopplung.

Was ich damit sagen will ist: Ein Auto Assoziert sein Lenkrad "stärker" als eine Workflow-Engine eine Buchhaltungskomponente.
oopexpert 06.05.2011
Beziehst Du Dich mit "Dependency Injection fordert den Bean-Charakter einer Klasse, um dynamisch zur Laufzeit die Assoziation aufbauen zu können." auf Property Injection?
Golo Roden 06.05.2011
Ich denke schon. Man sollte DI dort lassen, wo es hingehört: Für Modulkonfiguration großer Einheiten und nicht in die Fachklassen. ...ob ich eine Property setze oder eine Dependency aufbaue.
oopexpert 18.05.2011
2
Anders als gfoidl sehe ich hier sehr wohl Zusammenhänge:

Ein switch-case ist schlecht erweiterbar, hier gibt es durchaus geschicktere Möglichkeiten, "guten" Code zu schreiben (Stichwort Polymorphie). Und wenn man die einzelnen polymorphen Objekte per IoC injiziert, wird auch das noch mal schön entkoppelt.

Ein Artikel, der genau das beschreibt (zwar ohne IoC im Sinne eines Microkernels, aber letztlich lässt sich das leicht darauf adaptieren): http://csis.pace.edu/~bergin/patterns/ppoop.html

IMHO haben switch-case und OCP also sehr wohl miteinander zu tun, und ich finde die Argumentation des Fragestellers seinem Kollegen gegenüber sehr gut.
05.05.2011
Golo Roden 2,7k 3 9
0
Ich würde diese Switch Behauptung ein bisschen konkretisieren. Switch Anweisungen sind schlecht um große Flows zu steuern oder zwischen verschiedenen Verhalten zu wechseln, aber Switch Anweisungen können super für Algorithmen oder ähnliches sein.

Scala geht mit dem Pattern Matching da sogar einen Schritt weiter, was für einige Algorithmen, z.B. Merge Sort wirklich sehr nett ist und für asynchrone Programmierung über Aktoren und Nachrichten wirklich genial ist.

Polymorphie steht für manche Szenarien nicht zur Verfügung und da kann ein Switch, z.B. für einen Nachrichten-Typ oder ähnliches durchaus angebracht sein.
19.05.2011
sebastianstehle 444 6
0
Sehr oft handelt es sich bei großen Switches um Mappingstrukturen. Einem Datentyp wird eine Formatierung zu geordnet; Einem Typ die zu validierenden Felder , Zu einem Feld die Methode wie validiert werden soll....

Z.bsp. sowas:

int getNextPrime(int start,string algo)
{
switch(algo)
case "Normal":
algo = new NormalAlgo();
break;
....
}


Gerade in solchen Fällen ist es deutlich einfacher wenn das Mapping in einem eigenen strukturiertem Element vorliegt z.bsp. in einem Dictionary<T,U>. Ob dieses element intern definiert ist oder von aussen kommt (z.bsp. Injection,Configuration,...) lasse ich mal aussen vor.

Wenn aber eine Komponente ein solches Mapping auswertet oder gar selbst aufbaut, stellt sich mir aber die Frage ob die Architektur an sich optimal ist.

Imo sollte es eine Stelle geben die Entscheidet was / wie etwas getan werden sollte und dann lediglich irgendwo hin delegiert.

Bei Switches welche sich auf eine Art Type Mapping beziehen z.bsp. System.DbType auf den .NET Type finde ich eine Injiziierung eines IEnumerable<TKey,TValue> am einfachsten udn verständlichsten z.bsp.

Type resolvedType = TypeMapping.FromDbType(DbType.String);
20.05.2011
Gentlehag 1,0k 3 8
0
Halte ich nicht so viel davon, das ist auch nur ein verstecktes Switch. Bei Änderungen muss genauso die Enumeration geändert werden und eine neue Strategie registriert werden.
20.05.2011
sebastianstehle 444 6

Stelle deine Best-practice-Frage jetzt!