Inhalt Abbildung PDF Source OO-Designkurs
 |<    <     >    >|  Generated by CoCoDiL

2.2 Methoden

2.2.1 Extract Method

2.2.1.1 Einführung

void myMethod(){
  if (widgetId == #F0F898){  "ist Widget sichtbar"
    tueEtwas();
}

daraus wird:

boolean isWidgetVisible(){
  return widgetId == #F0F898
}
void myMethod(){
  if (isWidgetVisisble){
     tueEtwas();
  }
}

Was ist passiert?

Do not comment bad code, rewrite it

2.2.1.2 Idealer Design von Methoden

2.2.1.3 Vorteile kurzer Methoden

Bemerkung: Ein Coverageanalyse-Tool ist ein unentbehrliches Hilfsmittel für Tests. Es stellt fest, welche Klassen bzw. Methoden, wie oft und ggf. mit welchen Parametern aufgerufen worden sind. So kann man feststellen, welcher Bereich des Source Codes noch nicht ausreichend getestet worden ist. Einfache Coverageanalyse - Tools erkennen nicht welche Verzweigungen (z.B IFThenElse Block) innerhalb einer Methode aufgerufen worden ist. Deshalb verwende kleine Methoden, ohne groessere Verzweigungen

* Reusability through self encapsulation Mein Lieblingsartikel aus dem Plop1 Buch von Ken Auer. Es geht um grundsaetzliche Vorgehensweise beim Design einer Klasse

Extrahiere Methode ohne lokale Variable

void printOwing(){
Enumeration e = _orders.elements();
    double outstanding = 0.0 ;
// print banner
System.out.println ("*************************");
    System.out.println ("***** Customer Owes *****");
    System.out.println ("*************************");
// calculate outstanding
while (e.hasMoreElements()){
           Order each = (Order) e.nextElement();
           outstanding += each.getAccount();
    }
// printDetails
    System.out.println("name:" + _name);
    System.out.println("amount:" + outstanding);
}

Zuerst wird printBanner extrahiert, da in diesem Teil keine lokalen Variablen sind, ist diese Aktion besonders trivial.

void printOwing(){
Enumeration e = _orders.elements();
    double outstanding = 0.0 ;
printBanner();
// calculate outstanding
while (e.hasMoreElements()){
           Order each = (Order) e.nextElement();
           outstanding += each.getAccount();
    }
// printDetails
    System.out.println("name:" + _name);
    System.out.println("amount:" + outstanding);
}
void printBanner(){
    System.out.println ("*************************");
    System.out.println ("***** Customer Owes *****");
    System.out.println ("*************************");
}

Extrahiere Methode mit lokale Variablen

Jetzt wird printDetails extrahiert. Dabei wird eine lokale Variable outstanding benutzt, die als Parameter übergeben wird

void printOwing(){
Enumeration e = _orders.elements();
    double outstanding = 0.0 ;
printBanner();
// calculate outstanding
while (e.hasMoreElements()){
           Order each = (Order) e.nextElement();
           outstanding += each.getAccount();
    }
printDetails(outstanding)
}
void printBanner(){
    System.out.println ("*************************");
    System.out.println ("***** Customer Owes *****");
    System.out.println ("*************************");
}
void printDetails( double outstanding ){
    System.out.println ("name:" + _name);
    System.out.println ("amount" + outstanding);
}

Jetzt wird calculate outstanding extrahiert. Die lokale Variable outstanding kann in extrahierten Teil definiert werden. Da sie von printDetails noch gebraucht wird, muss sie als returnWert zurückgegeben werden

void printOwing(){
    printBanner();
    double outstanding = getOutstanding();
    printDetails(outstanding)
}
void printBanner(){
    System.out.println ("*************************");
    System.out.println ("***** Customer Owes *****");
    System.out.println ("*************************");
}
void printDetails( double outstanding ){
    System.out.println ("name:" + _name);
    System.out.println ("amount" + outstanding);
}
double getOutstanding(){
    Enumeration e = _orders.elements();
    double result = 0.0;
    while (e.hasMoreElements()){
      Order each = (Order) e.nextElement();
      result += each.getAmount();
    }
    return result ;
}

Refactoring Extract Method

2.2.1.4 Typisierung von Methoden

Eine einheitliche Benennung der Methoden vereinfacht die Lesbarkeit des Codes. Dirk Riehle hat im JavaReport eine * Typsierung von Methoden, je nach Verwendungszweck, sowie eine Einteilung nach * Methoden Eigenschaften vorgeschlagen. Jeder Methodentyp wird durch ein bestimmtes Prefix im Namen gekenndzeichnet. Hier ein Link zum * Original.

2.2.1.5 Method Object


Abb. 2.6: Eine komplizierte Methode

Einige Methoden lassen sich trotz grosser Anstrengungen nicht extrahieren. Dies liegt meist daran, daß sehr viele lokale Variablen verwendet werden, und innerhalb der Methode verschachtelte Kontrollstrukturen und Returns sind. In diesen Fällen hilft es, die Methode durch eine Klasse zu ersetzen. Da in dieser Klasse alle lokalen Variabeln der komplexen Methode als Instanzvariablen umgewandelt sind, lässt sich die Klasse leicht refaktorisieren.

  1. Erzeuge eine neue Klassen, mit dem Name der sich aus der Methode ergibt (Drucken).
  2. Erzeuge für jeden Parameter (printer,kopien) der Methode und für jede lokale Variable (textstil, format) ein Attribut.
  3. Erzeuge ein Attribut für das ursprüngliche Objekt (Dokument).
  4. Erzeuge für jedes Attribut des neuen Objekts die Accessor-Methoden.
  5. Verschiebe den Text der alten Methode in eine neue Methode compute des neuen Objekts.
  6. Ersetze in compute die Parameter und die lokalen Variabeln durch die Accessor-Methoden.
  7. Ersetze in compute die Referenzen auf das Ursprungsobjekt (i.a. this) durch die entsprechende Accessor-Methoden (getDokument).
  8. Gebe der neue Klasse einen Konstruktor mit folgenden Parametern.
  9. Ersetze im ursprünglichen Objekt die komplexe Methode durch den Aufruf der neuen Klasse und rufe die Methode compute auf.

Abb. 2.7: Methode in Klasse umgewandelt

Refactoring Replace Method with Method Object
Smalltalk Best Practice Patterns Method Object

Inhalt Abbildung PDF Source OO-Designkurs
 |<    <     >    >|  Generated by CoCoDiL