Prozedurale Strukturen Diskussion
 
StartSeite | Neues | TestSeite | ForumSeite | Teilnehmer | Kategorien | Index | Hilfe | Einstellungen | Ändern

Es gibt im RefactoringBeispiel sowohl eine "Treppen"-, als auch eine "Kamm"-Struktur. Inwiefern ist es sinnvoll, diese so miteinander zu vermischen?

// Codebeispiel 1

// Kammstruktur I
public static String eineMethode(String string){
  tuDies(string);
  tuDas(string);
  tuJenes(string);
  return string;
}

Genauso sieht es auch hier aus, da hier einfach mit dem Rückgabewert gearbeitet wird:

// Codebeispiel 2

// Kammstruktur II
public static String eineMethode(String string){
  return tuJenes(tuDas(tuDies(string)));
}

// Codebeispiel 3

// Treppenstruktur
public static String eineMethode(String string){
  // implementierte Funktionalität bzgl. string
  return tuJenes(string);
}

public static String tuJenes(String string){
  // implementierte Funktionalität bzgl. string
  return tuDas(string);
}

public static String tuDas(String string){
  // implementierte Funktionalität bzgl. string
  return tuDies(string);
}

public static String tuDies(String string){
  // implementierte Funktionalität bzgl. string
  return string;
}

Nun ist es aber so, daß dieses RefactoringBeispiel die Treppen- und die Kammstruktur miteinander vermischt und ich frage mich jetzt, nach welchen Kriterien vermischt wurde? Oder anders gefragt: wann sollte zu welcher Struktur hin refaktorisiert werden?


Zur Illustration betrachten wir Codebeispiel 1 und 3.

In 1 werden die Methoden in dieser Reihenfolge traversiert:

Die Kontrolle über den Ablauf liegt also komplett bei eineMethode.

Das Codebeispiel 3 ebenso dargestellt:

Hier wird die Kontrolle vollständig an die Untermethoden abgegeben und die Obermethode eineMethode bekommt erst wieder das Gesamtergebnis zu sehen.

Aus Software Engineering - Grundlagen, Methoden und Anleitung zum erfolgreichen Softwareprojekt, Zuser Wolfgang et al. Version 1.0 vom 31. Aug. 2000, ein Skriptum von der TU-Wien:

[Die Treppenstruktur] erhöht die Möglichkeit der Wiederverwendung von umfangreicher Funktionalität (da jeder Schritt viel Funktionalität kapselt). Auch die Wahrscheinlichkeit von Vererbung dieser Funktionalität ist hoch. Im Hinblick auf die Weiderverwendung von reinen Datenobjekten (welche keine Geschäftslogik implementieren) besitzt [die Kammstruktur] Vorteile, da diese ohne jegliche interne Konsistenzprüfung (die Konsistenzbedingungen wecheln von System zu System) leichter wiederzuverwenden sind. Betrachtet man den Aspekt der Wartbarkeit, ist ebenfalls [die Kammstruktur] von Vorteil, da die Änderungen an einer zentralen Stelle durchgeführt werden.

weitere Diskussion

Ich glaube nicht, dass man diese Frage pauschal beantworten kann - besser geeignet ist IMHO immer diejeniege Struktur, die besser ausdrückt, was eigentlich passiert. Im wesentlichen ist es IMO vorteilhaft, wenn der Inhalt einer Methode sich auf einem gemeinsamen Abstraktionslevel befindet und betrachtet werden kann, als würde er eine neue atomare Aktion formen. Meist korreliert das recht gut zu den beiden Eigenschaften "liest sich der Rumpf flüssig" und "finde ich einen guten Methodennamen", denke ich.

Wann Du zu welcher Struktur hin refaktorisieren solltest, ist eine gute Frage! Ich habe die vorhandene Struktur beim RefactoringBeispiel so gewählt, weil sie mir den Algorithmus recht deutlich zu kommunizieren schien, habe aber auch nicht viel über Alternativen nachgegrübelt. Wie sieht der Algorithmus denn aus, wenn Du ihn zu Deiner Variante refaktorisiert hast? -- IljaPreuß

Ich grübel noch ein wenig...:-)
... und komme, was das Refactoring betrifft, auf keinen grünen Zweig. Allerdings ist mir bei der Spielerei mit dem Code noch eine Verbesserung aufgefallen in der Methode longestConsecutiveMatch. Da kann man noch eine zusätzliche Abfrage einfügen. Fällt nicht gerade mit dem "Mississippi"-Testwort ins Gewicht, aber bei z.B. "MississippiMississippi?" macht das schon ca. 12,5% mehr Geschwindigkeit aus. Hier der Code dazu:
    private static String longestConsecutiveMatch(String[] strings) {
        String currentLongest = "";
        for (int index = 0; index < strings.length - 1; index++) {
            final int currentLength = headingMatchLength(strings[index], strings[index + 1]);
            if (currentLength > currentLongest.length()) {
                currentLongest = strings[index].substring(0, currentLength);
            }
            if(currentLongest.length() > index + 2){
                break;
            }
        }
        return currentLongest;
    }

Das hinzugefügte habe ich rot hinterlegt. -- bs

Ich bin mir nicht sicher, ob ich etwas beitragen kann, aber ich versuche es. Erstens glaube ich nicht, dass das ein imperativ vs OO Problem ist, obwohl es nach aussen so wirkt. Es scheint mir mehr wie ein API-Design-Problem, das mit der Frage der Wiederverwendung verknüpft ist und gleichzeitig auf (IMHO) Mängel in der derzeitigen OO-Philosophie hinweist. Wenn man Basismethoden wie tuDies, tuDas und tuJenes hat, dann ist es legitim, davon Methoden wie tuDiesDas, tuDasJenes oder tuDiesDasJenes abzuleiten. Das kann reine Bequehmlichkeit sein, könnte aber auch den Schutz vor einer fehlerhaften Reihenfolge beinhalten. Wenn die Basismethoden aber orthogonal sind, dann haben die Kombinationsmethoden Utility-Character und gehören eigentlich nicht zum Kern der Objekt-Implementierung. Aber wo gehören sie hin? Was ist ihr natürlicher Platz im Namespace? Das ist eine Frage, mit der ich Ilja in anderem Zusammenhang schon geplagt habe.

Ich denke, das lässt sich so abstrakt nicht entscheiden. Ich kann mich ehrlich gesagt auch nicht mehr recht an unsere vorherige Diskussion erinnern (war das in news:comp.object?) - hatten wir da ein konkreteres Beispiel?

Werden die Kombinationsmethoden ins Objekt gesteckt, dann blähen sie es unnotwendig auf (und nichts in der OO-Philosophie beschäftigt sich mit diesem Problem) und ausserdem geht das nur in der speziellen Situation, wenn man über die Kompetenz (Source, Rechte) für das Objekt verfügt. Werden die Kombinationsmethoden aber in irgendeine Utility-Klasse gesteckt, so verschlechtern sie die Wiederverwendbarkeit allgemein, vor allem aber über Projektgrenzen hinweg (was kein OO-Mensch gerne hört). -- HelmutLeitner

Mhh, ich habe das Gefühl, dass das eher technische Probleme sind, die von unterschiedlichen Sprachen mit unterschiedlichem Erfolg gelöst werden. So kann man z.B. in der SpracheSmalltalk Methoden verschiedenen Kategorien zuordnen und nur innerhalb bestimmter Applikationen definieren. In der SpracheRuby kann man meines Wissens nach sogar einzelne Objekte zur Laufzeit um neue Methoden ergänzen, was vermutlich nicht mehr Kompetenz erfordert als die Methode in eine Utility-Klasse zu packen. Ich sehe ehrlich gesagt auch nicht ganz, wie eine Utility-Klasse im Allgemeinen die Wiederverwendbarkeit verschlechtert... habe aber das Gefühl, dass wir uns da schonmal uneins waren... ;) -- ip


Zu der Thematik habe ich mal was gelesen, ich glaube es war Kent Beck's "Smalltalk Best Practice Patterns", kann aber auch "Design Patterns" der GangOfFour gewesen sein. Egal, woher es nun stammt, ich fand es einleuchtend. Mit eigenen Worten wiedergegeben: Alle Methoden innerhalb eines "Kamms" sollten in etwa den gleichen Abstraktionsgrad besitzen.

Ja, es stammt aus dem DesignPatternBuch der GangOfFour. --bs

Also wäre folgendes nicht sinnvoll:

def fuehreKammAus
    tueWasSimples1
    tueWasSimples2
    tueWasKompliziertes
    tueWasSimples3
end

(PseudoCode entlehnt aus SpracheRuby)

Ob und inwieweit ich eine Methode wiederverwenden kann, muss zwar ebenfalls berücksichtigt werden, Betrachtung der Komplexität ist aber ein erster Schritt weg von der prozeduralen Denke. In dem Moment, wo meine Klasse durch Methoden unterschiedlicher Komplexität unübersichtlich wird, kann ich anfangen über Auslagerung dieser Anteile in eigene Klassen nachzudenken. Ziel des Ganzen sollte nicht der höchstmögliche Grad an Wiederverwendung, sondern eine gute Lesbarkeit sein. Bequemlichkeit sollte dabei überhaupt keine Rolle spielen. Auf Methoden tueDiesUndDannDas ist vorzugsweise dann zu verzichten, wenn

Ich sehe in dem, was direkt nach "weitere Diskussion" kursiv steht, eine sinnvolle Antwort. Es gibt ziemlich genau wieder, was ich hier nochmal mit anderen Worten aufgedröselt habe. -- SDö
KategorieDiskussion
StartSeite | Neues | TestSeite | ForumSeite | Teilnehmer | Kategorien | Index | Hilfe | Einstellungen | Ändern
Text dieser Seite ändern (zuletzt geändert: 3. Juni 2004 12:41 (diff))
Suchbegriff: gesucht wird
im Titel
im Text