Refactoring Java Code - PowerPoint PPT Presentation

About This Presentation
Title:

Refactoring Java Code

Description:

Title: Eine Pattern-Sprache zur Strukturierung gro er Software-Systeme mit Java Author: Arno Haase Last modified by: Arno Haase Created Date: 11/5/2001 7:52:24 AM – PowerPoint PPT presentation

Number of Views:170
Avg rating:3.0/5.0
Slides: 135
Provided by: ArnoH
Category:

less

Transcript and Presenter's Notes

Title: Refactoring Java Code


1
Refactoring Java Code
Arno.Haase_at_Haase-Consulting.com Arno.Haase_at_acm.org
www.Haase-Consulting.com
2
Übersicht
  • ? Einführung
  • Das Umfeld für Refactoring
  • Code Smells als Wegweiser
  • Automatisierte Tests mit JUnit
  • Konkrete Refactorings
  • Beispiel
  • Toolunterstützung

3
Refactoring, Martin Fowler
  • Dieses Tutorial beruht im Wesentlichen auf dem
    Buch Refactoring Improving the Design of
    Existing Code von Martin Fowler.
  • Standardwerk
  • Abweichungen im Detail

4
Refactoring Definition
Refactoring ist die Verbesserung der
Qualität von vorhandenem Quell- text ohne
Veränderung der Funktionalität.
5
Problem
  • Das Design eines Systems neigt dazu, im Laufe der
    Zeit immer schlechter zu werden.
  • Neue Funktionalität wird gefordert, alte entfällt
  • Vorhandene Anforderungen werden geändert
  • Das Verständnis des Systems ändert sich

6
Refactoring als Gegenmittel
  • Um dem entgegenzuwirken, muss das Design mit dem
    System wachsen.
  • Kleine Schritte reduzieren das Risiko
  • Trennung zwischen Refactoring und Erweiterung des
    Systems hilft zu fokussieren
  • Arbeit am System stößt auf sich ändernde Teile

7
Demonstration
  • Ein Quelltext sagt mehr als tausend Folien...
  • Der Quelltext ist im Internet verfügbar
    www.haase-consulting.com/download/oop2002

8
Was ist geschehen?
  • Ein Stück Software wurde überarbeitet, ohne dass
    sich sein Verhalten geändert hat.
  • Auslöser eine anstehende Änderung
  • Code war unnötig kompliziert
  • Änderungen in kleinen Schritten

9
Wann Refactoring
  • Der richtige Zeitpunkt für Refactoring ist, wenn
    man sich ohnehin mit dem Quelltext beschäftigt.
  • Beim Debugging
  • Beim Erweitern/Ändern
  • Wenn ein Kollege mit einer Frage kommt

10
Kleine Schritte
  • Refactoring funktioniert am besten, wenn man es
    in kleinen Schritten tut.
  • Schutz vor Flüchtigkeitsfehlern
  • Man behält den Überblick
  • Bei Problem einfach einen Schritt zurück

11
Die beiden Hüte
  • Refactoring und Erweiterung des Systems wechseln
    sich ab.
  • Saubere Trennung für besseren Überblick
  • Zettel und Stift als Gedächtnisstütze
  • Man hat entweder den Refactoring-Hut oder den
    Erweiterungs-Hut auf

12
Zusammenfassung
  • Refactoring erlaubt es, nachträglich
    Designentscheidungen zu ändern.
  • Zeitpunkt wenn man ohnehin mit dem Code zu tun
    hat
  • Kleine Schritte Entspannt bleiben, bei Problem
    einen Schritt zurück.

13
Übersicht
  • Einführung
  • ? Das Umfeld für Refactoring
  • Code Smells als Wegweiser
  • Automatisierte Tests mit JUnit
  • Konkrete Refactorings
  • Beispiel
  • Toolunterstützung

14
Altersschwäche
  • Software kann an Altersschwäche sterben.
  • Design wächst nicht mit den Anforderungen
  • Wartung als Albtraum
  • Manchmal schon vor Inbetriebnahme...

15
Hellseherei
  • Fixiertes Design vorab ist problematisch.
  • Anforderungen ändern sich
  • Das Verständnis wächst
  • Hellseherei funktioniert oft nicht
  • Ausnahme feste Anforderungen, erfahrenes Team
    (z.B. reine Migration)

16
Traditionelles Vorgehen
  • Das Wasserfall-Modell ist immer noch sehr
    verbreitet.
  • Änderungen werden mit der Zeit teurer
  • Risiko minimieren

17
Änderungen billig machen
  • Agile Vorgehensmodelle unterstützen späte
    Änderungen
  • Z.B. eXtreme Programming
  • Weniger Gewicht auf Planung am Anfang
  • System profitiert von wachsender Erfahrung

18
Kriterien für das Vorgehensmodell
  • Refactoring funktioniert am besten in einem
    Vorgehensmodell, bei dem Änderungen
  • billig und
  • sicher sind.
  • Dann kann das System von der wachsenden Erfahrung
    profitieren.

19
Source-Code enthält das Design
  • Refactoring ändert das Design schrittweise im
    Quelltext. Sonstige Design-Dokumentation bremst
    dabei.
  • Keine Hackerei Anforderung an den Code
  • Je feiner die übrige Designdokumentation ist,
    desto problematischer
  • Design Freeze schließt Refactoring aus

20
Einfachheit als Wert
  • Softwareentwicklung ist eine der kompliziertesten
    Tätigkeiten der Welt.
  • Quelltexte sind primär für menschliche Leser
  • Möglichst viele Hilfestellungen
  • Unnötige Komplexität entfernen

21
Wenn du es siehst, tue es
  • Ein Problem lieber gleich angehen als es auf die
    lange Bank schieben.
  • Probleme verschwinden nicht von alleine
  • Vorgehensmodell muss das zulassen
  • Mut als Wert
  • Ausnahme kurz vor einer Deadline.

22
Qualität als Wert?
  • Qualität als Wert entwickelt leicht eine
    Eigendynamik.
  • Qualität ist relativ zu Maßstäben damit lässt
    sich Vieles begründen
  • Stattdessen klarer Einfachheit und
    Kommunikation

23
Versionsverwaltung
  • Eine Versionsverwaltung ist eine wichtige
    Voraussetzung für Refactoring, besonders im Team.
  • Reversibilität von Refactorings
  • Kurze Check-In-Zyklen

24
Buildprozess
  • Nur ein wohldefinierter Buildprozess erlaubt die
    Überprüfung von Änderungen.
  • An jedem Arbeitsplatz verfügbar
  • Muss gelebt werden ? Integration in IDE
  • Früh aufsetzen und mit dem Projekt wachsen lassen

25
Häufige Integration
  • Es muss immer ein funktionstüchtiger Stand des
    Systems verfügbar sein.
  • Systemteile früh aneinanderschrauben, damit sie
    nicht auseinanderlaufen
  • z.B. nächtlicher Build

26
Einwände gegen Refactoring
  • Es gibt teilweise tatsächliche Hindernisse
  • Design ist nicht mehr dokumentiert.
  • Refactoring lohnt sich nicht.
  • Wo sind die kurzfristigen Vorteile?
  • Es könnte etwas kaputtgehen.

27
Design ist nicht dokumentiert
  • Einwand Durch Refactoring laufen Implementierung
    und Designdokumentation auseinander
  • Im sehr großen Maßstab berechtigter Einwand
  • Ansonsten
  • Gesonderte Designdokumentation veraltet ohnehin
  • Quelltext gewinnt an Klarheit Design wird im
    Quelltext expliziter

28
Refactoring lohnt sich nicht
  • Einwand Während des Refactorings implementiert
    man keine Funktionalität.
  • Durch Refactoring gleichbleibend gutes Design
  • System bleibt änderbar
  • Nicht ästhetische Selbstbefriedigung

29
Keine kurzfristigen Vorteile
  • Einwand Refactoring bringt langfristig Vorteile,
    aber nicht kurzfristig.
  • Refactoring als Teil des jeweiligen Arbeitspakets
  • Kein Hauruck-Redesign, sondern hier ein wenig und
    dort ein wenig.
  • Vereinfacht die tägliche Arbeit und spart dabei
    Zeit.

30
Es könnte etwas kaputt gehen
  • Einwand Refactoring könnte bestehende
    Funktionalität kaputt machen.
  • JUnit-Tests
  • In kleinen Schritten vorgehen
  • Bei Unsicherheit lieber vorsichtig sein
  • Andererseits bei jeder Änderung kann etwas
    kaputtgehen...

31
Alternative Einfach tun
  • Wenn das Management nicht von Refactoring
    überzeugt ist, gibt es die Möglichkeit, es
    einfach zu tun
  • Der offizielle Weg ist besser
  • Professionelle Verantwortung
  • Es spart Zeit, wird sich also bewähren

32
Grenzen des Refactoring
  • Es gibt Situationen, wo Refactoring nicht gut
    funktioniert.
  • Relationale Datenbanken
  • Fixierte Schnittstellen
  • Hoffnungslos kaputtes System

33
Zusammenfassung
  • Das Umfeld des Refactoring
  • Agile Prozesse erlauben es, spät Änderungen am
    System durchzuführen
  • Versionsverwaltung, Build Management
  • Es gibt Einwände, mit denen man sich auseinander
    setzen muss
  • Refactoring ist lernbar Keine Scheu!

34
Übersicht
  • Einführung
  • Das Umfeld für Refactoring
  • ? Code Smells als Wegweiser
  • Automatisierte Tests mit JUnit
  • Konkrete Refactorings
  • Beispiel
  • Toolunterstützung

35
Wann Refactoring?
  • Das wie ist relativ einfach, aber wann und wo
    soll man refaktorieren?
  • Lohnt sich ein bestimmtes Refactoring?
  • In welche Richtung soll man gehen?
  • Wo fängt man an?
  • Wann soll man aufhören?

36
Code Smells
  • Geruch von Quelltexten ist eine Metapher, um
    über ihre Qualität zu reden.
  • Katalog von Gerüchen
  • Keine präzisen Kriterien
  • Hilfestellung für die Intuition

37
Duplizierter Code
  • Wenn das Gleiche an zwei Stellen im Quelltext
    steht, stinkt das zum Himmel.
  • Der Quelltext ist unübersichtlich
  • Das System ist schwer zu ändern
  • Inkonsistenzen und damit Fehler schleichen sich
    ein

38
Datenklasse
  • Eine Klasse, die nur Daten und keine Logik
    enthält, ist ein Indiz für Verbesserungs-potential
  • Oft gibt es Funktionalität, die im Wesentlichen
    auf diesen Daten operiert
  • Andernfalls ist vielleicht die Klasse schlecht
    geschnitten

39
Kommentare
  • Kommentare an sich riechen gut, sie werden aber
    oft als Deodorant verwendet.
  • Kommentare sind Zeichen, dass der Quelltext
    selbst nicht klar verständlich ist
  • Kommentare können veralten oder in die Irre führen

40
Unangebrachte Intimität
  • Zwei Klassen, die ausgiebig gegenseitig Methoden
    aufrufen, sind oft nicht gut geschnitten.
  • Sie sind eng gekoppelt und schwierig unabhängig
    voneinander zu ändern
  • Sie sind schwierig zu benutzen, weil sie keine
    klare Aufgabenteilung haben

41
Neid
  • Eine Methode, die im Wesentlichen auf Attributen
    einer anderen Klasse operiert, ist dort
    wahrscheinlich besser aufgehoben.
  • Die Signatur der Methode wird dann einfacher und
    die Aufgabenteilung der Klassen natürlicher

42
Switch
  • Fallunterscheidungen mit switch führen oft zu
    doppeltem Code, weil die gleichen Fälle mehrmals
    unterschieden werden.
  • Switch ist nicht typsicher
  • Man vergisst leicht Fälle
  • Zusätzliche Fälle müssen an vielen Stellen
    bedacht werden

43
Lange Methode
  • Lange Methoden sind aufwendiger zu verstehen als
    kurze.
  • Kurze Methoden können durch ihre Namen den
    Quelltext dokumentieren
  • Durch Extrahieren kurzer Methoden kann man
    Code-Duplizierung vermeiden und Aufgaben
    zwischen Klassen verschieben

44
Monster-Klasse
  • Eine zu große Klasse wird unübersichtlich.
  • Zu viele Attribute führen leicht zu
    Code-Duplizierung

45
Datenklumpen
  • Eine Gruppe von Daten, die oft zusammen vorkommt,
    kann man oft als Klasse zusammenfassen.
  • Dieser Typ kann Funktionalität bekommen und
    dadurch doppelten Code vermeiden
  • Die Verwendung der Daten wird einfacher


?
46
Unechte Primitive Datentypen
  • Primitive Datentypen können oft besser durch
    Klassen ersetzt werden.
  • Eigene Werttypen sind typsicher und dokumentieren
    den Code
  • Manchmal gibt es falsche Scheu vor kleinen
    Klassen

?
47
Schrotkugeln herausoperieren
  • Wenn man viele Klassen ändern muss, um einen
    Aspekt zu ändern, ließe er sich vielleicht an
    einer Stelle lokalisieren.
  • Man übersieht sonst leicht eine Stelle
  • Es entsteht leicht doppelter Code

48
Kombinierte Abstraktionen
  • Wenn eine Klasse von vielen verschiedenen
    Änderungen betroffen wird, ist es vielleicht
    besser, sie zu spalten.
  • Sonst betreffen Änderungen potentiell mehr
    Quelltext als nötig
  • Aufteilung macht den Code übersichtlicher

49
Lange Parameterliste
  • Eine lange Parameterliste deutet auf
    Verbesserungspotential hin.
  • Lange Parameterlisten sind unübersichtlich
  • Sie neigen dazu, sich zu ändern
  • Attribute oder Parameterobjekte sind besser

50
Faule Klasse
  • Eine Klasse, die fast nichts mehr tut, kann mehr
    im Weg sein als nützen.
  • Jede Klasse bedeutet Komplexität
  • Der Nutzen kann kleiner werden als der Preis

51
Hellseherei
  • Oft berücksichtigen Leute sicherheitshalber
    Erweiterungen, die eventuell später benötigt
    werden.
  • Das Design wird komplizierter, schwieriger zu
    verstehen und ändern
  • Indiz Eine Methode oder Klasse wird nur von
    Tests verwendet

52
Methodenketten
  • Wenn man erst eine Reihe von get-Methoden
    aufrufen muss, um das eigentlich interessante
    Objekt zu bekommen, durchbricht das die
    Kapselung.
  • Änderungen der dazwischenliegenden Klassen
    betreffen den Client

53
Vermittler
  • Wenn viele Methoden einer Klasse den Aufruf
    einfach nur durchreichen, macht das das Interface
    unnötig kompliziert.
  • Der Client sollte stattdessen direkt mit dem
    inneren Objekt reden

54
Alternative Klassen mit verschiedenen
Schnittstellen
  • Wenn mehrere Klassen das Gleiche tun, bedeutet
    das Code-Duplizierung mit allen ihren Problemen.
  • Das gilt insbesondere bei unterschiedlichen
    Interfaces

55
Ausgeschlagenes Erbe
  • Wenn eine Unterklasse wesentliche Teile der
    Basisklasse ignoriert, irritiert das menschliche
    Leser.
  • Wenn Implementierung ignoriert wird, ist das
    nicht so schlimm
  • Wenn Teile der Schnittstelle nicht unterstützt
    werden, ist die Vererbung falsch

56
Übersicht
  • Einführung
  • Das Umfeld für Refactoring
  • Code Smells als Wegweiser
  • ? Automatisierte Tests mit JUnit
  • Konkrete Refactorings
  • Beispiel
  • Toolunterstützung

57
Automatisierte Modultests
  • Automatisierte Modultests reduzieren das Risiko
    beim Refactoring.
  • automatisiert Die Tests laufen auf Knopfdruck ab
    und brauchen keine Nutzeraktion.
  • Modultests Getestet werden die einzelnen Klassen.

58
JUnit
  • JUnit ist ein Framework zur Unterstützung von
    automatisierten Modultests.
  • Tests sind Java-Klassen
  • Test-Schreiben ist kein großer Overhead
  • www.junit.org

59
Beispiel
  • Ein dummes aber einfaches Beispiel...
  • Der Quelltext ist im Internet verfügbar
    www.haase-consulting.com/download/oop2002

60
Integration in IDE
  • Der Aufruf von JUnit ist einfach.
  • junit.jar in den ClassPath
  • junit.swingui.TestRunner als Main-Klasse
  • Den Namen des Testfalls als Kommandozeilenparamete
    r

61
Eine Testklasse je Klasse
  • Typischerweise schreibt man zu jeder Klasse eine
    Testklasse.
  • Testklasse erbt von junit.framework.TestCase
  • Per Namenskonvention endet der Name der
    Testklasse mit Test

TestCase
BriefmarkeTest
Briefmarke
62
Tests
  • Zu einer Test-Klasse gehören mehrere
    Test-Methoden.
  • Namenskonvention public void test... ()
  • Die Reihenfolge der Ausführung steht nicht fest
  • Die Testmethoden müssen unabhängig voneinander
    sein

63
Assertions
  • Die eigentlichen Tests erfolgen als Aufrufe der
    assert...-Methoden von TestCase.
  • Wenn die Bedingung erfüllt ist, passiert nichts
  • Wenn die Bedingung nicht erfüllt ist, wird
    dieser Test abgebrochen und als fehl-geschlagen
    vorgemerkt

64
TestSuite
  • Mehrere Tests können als TestSuite
    zusammengefasst werden.
  • Klasse junit.framework.TestSuite
  • Eine TestSuite kann TestCases und TestSuites
    enthalten

1..
Test
TestCase
TestSuite
65
Beispiel (2)
  • Eine zweite Klasse mit Tests kommt dazu.
  • Der Quelltext ist im Internet verfügbar
    www.haase-consulting.com/download/oop2002

66
Test vor Implementierung
  • Man kann den Test schon beim Nachdenken über die
    geplante Funktionalität schreiben.
  • Kleine Schritte Ein wenig Testen, ein wenig
    Implementieren usw.
  • Wenn der Test erfolgreich durchläuft, ist man
    fertig

67
Erst fehlschlagen lassen
  • Das Ausprobieren des Tests vor der
    Implementierung gibt Sicherheit.
  • Vielleicht klappt er ja schon...
  • Man stellt sicher, dass er tatsächlich ausgeführt
    wird

68
Tests als Dokumentation
  • Die Tests dokumentieren die getesteten Klassen
    genau.
  • Sie zeigen die nötige Initialisierung
  • Sie enthalten ein Beispiel für jede Methode
  • Die Dokumentation ist nie veraltet

69
Beispiel (3)
  • Das Beispiel wird noch einmal erweitert.
  • Der Quelltext ist im Internet verfügbar
    www.haase-consulting.com/download/oop2002

70
Tests als Sicherheitsnetz
  • Gute Tests schützen davor, unbeabsichtigt
    Funktionalität zu ändern, auf die sich andere
    Klassen verlassen.
  • Das ist eine Voraussetzung für zuversichtliches
    Refactoring
  • Es hilft auch bei Erweiterungen und Änderungen

71
Wie fängt man an?
  • Tests Schreiben braucht Übung, aber
  • der Einstieg ist leicht
  • eine unvollständige Test-Suite ist hilfreich und
    kann organisch wachsen
  • durch Refactoring kann man später die Tests
    verbessern
  • Testen macht Spaß

72
Zusammenfassung
  • Refactoring
  • Das Umfeld von Refactoring
  • Code Smells
  • JUnit

73
Übersicht
  • Einführung
  • Das Umfeld für Refactoring
  • Code Smells als Wegweiser
  • Automatisierte Tests mit JUnit
  • ? Konkrete Refactorings
  • Beispiel
  • Toolunterstützung

74
Katalog
  • Der Katalog ist Hilfestellung.
  • Ziel ist besserer Geruch Eigenes Urteil!
  • Probieren und Fehler sind ungefährlich
  • JUnit-Tests
  • Man kann alles rückgängig machen
  • Einstieg Problem
  • Konkrete Schritte damit man nichts vergisst
  • Am Ende Immer compilieren und testen

75
Change Inconsistent Layout
  • Quelltext ist inkonsistent formatiert,
    insbesondere eingerückt.
  • Layout an Quelltextrichtlinien anpassen
  • Möglichst toolgestützt
  • NICHT den eigenen Geschmack aufzwingen!

76
Replace Magic Number with Symbolic Constant
  • In einer Methode steht eine Zahl (außer 0 und 1).
  • Besser eine benannte Konstante einführen
  • Name ist Dokumentation
  • Wert ist besser änderbar
  • Typcode, Arraylänge o.ä.? Dann Alternative wählen

77
Replace Temp with Query
  • Eine temporäre Variable enthält ein
    Zwischenergebnis.
  • Den entsprechenden Ausdruck in eine Methode
    auslagern
  • Ursprüngliche Methode wird übersichtlicher
  • Verfügbar im ganzen Objekt

78
Rename Method (1)
  • Der Name einer Methode spiegelt nicht (mehr)
    ihren Inhalt wieder.
  • Den Namen ändern
  • Analog Parameter hinzufügen oder entfernen

79
Rename Method (2)
  • Konkrete Schritte
  • Basis- und Unterklassen prüfen
  • Methode mit neuem Namen anlegen, Implementierung
    hineinkopieren, compilieren
  • Clients schrittweise umstellen, jeweils testen
  • Ursprüngliche Methode löschen, Testen

80
Replace Constructor with Factory Method
  • Konstruktor ist nicht flexibel genug.
  • Besser statische create-Methode verwenden
  • Kontrolle über Instanzierung (Unterklassen,
    Caching, Referenz-Semantik)
  • Expliziter Name dokumentiert

81
Extract Method (1)
  • Mehrere Statements einer Methode gehören logisch
    zusammen.
  • Auslagern in eigene Methode
  • Sprechender Name für die neue Methode
  • Ursprüngliche Methode wird übersichtlicher

82
Extract Method (2)
  • Konkrete Schritte
  • Neue Methode anlegen und gut benennen
  • Implementierung hineinkopieren
  • Notwendige Parameter anlegen und benennen
  • Ggf. Rückgabewert einführen
  • Compilieren
  • Code in ursprünglicher Methode durch Aufruf
    ersetzen

83
Inline Method (1)
  • Der Code einer Methode ist genauso klar wie ihr
    Name.
  • Methode inlinen
  • Unnötige Methode ist nur Ballast
  • Gegenstück zu Extract Method

84
Inline Method (2)
  • Konkrete Schritte
  • Prüfen, dass die Methode nicht polymorph ist
  • Jeden Aufruf durch den Inhalt ersetzen
  • Compilieren und testen
  • Methode löschen
  • Bei Komplikationen nicht inlinen

85
Remove Assignments to Parameters
  • Eine Methode enthält eine Zuweisung an einen
    Parameter.
  • Stattdessen temporäre Variable verwenden
  • Erhöht Übersichtlichkeit

86
Replace Method with Method Object (1)
  • Eine Methode verwendet lokale Variablen so, dass
    Extract Method schwierig ist.
  • Neue Klasse anlegen, die der Methode entspricht
  • Lokale Variablen werden zu Attributen
  • Danach ist Refactoring leicht

87
Replace Method with Method Object (2)
  • Konkrete Schritte
  • Neue Klasse anlegen
  • Referenz auf ursprüngliche Klasse sowie Attribute
    für die lokalen Variablen einführen
  • Konstruktor zur Initialisierung
  • Methode compute einführen und die ursprüngliche
    Implementierung hineinkopieren
  • In der alten Methode an die neue delegieren

88
Substitute Algorithm
  • Ein Algorithmus ist komplizierter als nötig.
  • Durch einen einfacheren Algorithmus ersetzen
  • Insbesondere, wenn zwei verschiedene Algorithmen
    für das Gleiche verwendet werden
  • Optimierung allenfalls am Ende

89
Move Method (1)
  • Eine Methode benutzt mehr Features oder wird von
    mehr Features einer anderen Klasse benutzt als
    der, wo sie definiert ist.
  • Methode zu den Features verschieben
  • Stärkere Kohäsion, schlankere Schnittstellen
  • Das Original delegiert oder wird gelöscht

90
Move Method (2)
  • Konkrete Schritte
  • Benutzte Felder und Methoden ggf. mitverschieben
  • Vererbungshierarchie prüfen
  • Methode in der neuen Klasse deklarieren
  • Implementierung hineinkopieren und anpassen
  • Compilieren
  • Aufrufe ändern oder alte Methode umbiegen

91
Move Field (1)
  • Ein Feld wird in einer anderen Klasse mehr
    benutzt
  • Dorthin verschieben
  • Bessere Kohäsion und schlankere Schnittstelle
  • Eventuell Methoden mitverschieben

92
Move Field (2)
  • Konkrete Schritte
  • In Zielklasse ein Feld mit get- und set-Methode
    anlegen
  • Navigation von alter zu neuer Klasse
    sicherstellen
  • Ursprüngliches Feld entfernen
  • Zugriffe umbiegen (inkl. Unterklassen)
  • Compilieren und testen

93
Extract Class (1)
  • Eine Klasse macht die Arbeit von zweien.
  • Neue Klasse anlegen und Felder und Methoden
    hineinverschieben
  • Übersichtlichkeit durch klare Aufgabenteilung

94
Extract Class (2)
  • Konkrete Schritte
  • Aufteilung planen
  • Neue Klasse anlegen, Referenz von alter zu neuer
  • Einzelne Felder und Methoden verschieben
  • Schnittstellen überarbeiten
  • Ggf. neue Klasse veröffentlichen (Referenz/Wert)

95
Hide Delegate
  • Ein Client holt sich von einem Objekt ein anderes
    Objekt und ruft darauf eine Methode auf.
  • Im ersten Objekt eine Methode erzeugen, die dann
    delegiert
  • Dadurch bessere Kapselung

96
Remove Middle Man
  • Eine Klasse delegiert eine Reihe von Aufrufen
    einfach an ein anderes Objekt.
  • Stattdessen inneres Objekt herausreichen
  • get-Methode einführen
  • Dadurch Übersichtlichkeit erhöhen

97
Replace Data Value with Object
  • Ein primitives Attribut hat eigentlich
    dazugehörige Funktionalität.
  • Spezielle Klasse schaffen und deren Instanz
    verwenden
  • Clients nach und nach umstellen
  • Wert-Semantik Identität spielt keine Rolle

98
Replace Type Code with Subclass (1)
  • Eine Klasse hat einen Typcode, der über das
    Verhalten entscheidet.
  • Für jeden Wert des Typcodes eine Unterklasse
  • Grundlage für weitere Refactorings

99
Replace Type Code with Subclass (2)
  • Konkrete Schritte
  • Auf Typcode nur durch get-Methode zugreifen
  • statische create-Methode einführen
  • Für jeden Wert eine Unterklasse einführen, die
    die get-Methode überschreibt
  • Typcode-Attribut aus der Basisklasse entfernen

100
Replace Type Code with State/Strategy (1)
  • Ein Typ-Code entscheidet über Verhalten, aber es
    gibt schon Unterklassen.
  • Zweite Vererbungshierarchie für Typ-Code
  • Als State/Strategy anbinden

101
Replace Type Code with State/Strategy (2)
  • Konkrete Schritte
  • Den Typ-Code hinter get-Methode kapseln
  • Neue Klasse mit Unterklassen für jeden Wert
    schaffen (State-Klasse)
  • Typ-Code in die neue Klassenhierarchie
    verschieben
  • Beim Setzen des Typ-Codes stattdessen State
    ändern
  • Typ-Feld entfernen

102
Replace Conditional with Polymorphism (1)
  • Verhalten wird über einen Typ-Code ausgewählt.
  • Für jeden Typcode eine Unterklasse
  • Spezifisches Verhalten jeweils in einer
    überschriebenen Methode
  • Man vergisst keine Fälle und gruppiert Logik

103
Replace Conditional with Polymorphism (2)
  • Konkrete Schritte
  • Replace Type Code with ...
  • Ggf. Fallunterscheidung in eigene Methode
  • Der Reihe nach
  • Für Unterklassen die Methode überschreiben und
    testen
  • Den Fall aus der ursprünglichen Methode entfernen
    und testen
  • Methode in der Basisklasse abstrakt machen

104
Replace Subclass with Fields (1)
  • Unterklassen unterscheiden sich nur in Methoden,
    die konstante Werte liefern.
  • Die Unterklassen entfernen und die Werte aus
    Attributen holen
  • Die Unterklassen sind unnötiger Ballast geworden

105
Replace Subclass with Fields (2)
  • Konkrete Schritte
  • Statische create-Methode einführen
  • final Felder in der Basisklasse einführen mit
    protected Konstruktor, der sie initialisiert
  • Unterklassen so ändern, dass sie diesen aufrufen
  • Die Methoden in der Basisklasse ändern, so dass
    sie die Werte der Felder liefern
  • Unterklassen entfernen

106
Consolidate Duplicate Conditional Fragments
  • Ein gemeinsames Stück Code ist in allen Zweigen
    einer Fallunterscheidung.
  • Gemeinsamen Code herausziehen
  • Entweder davor oder dahinter
  • Sonst eventuell in eigene Methode

107
Remove Control Flag
  • Ein Flag kontrolliert den Ablauf einer Schleife.
  • Besser break, continue und return verwenden
  • Kürzer und übersichtlicher

108
Replace Nested Conditional with Guard Clause
  • Eine Methode hat verschachtelte if-Statements, um
    ohne zweites return auszukommen.
  • Sonderfälle am Anfang behandeln und dort direkt
    zurückkehren
  • Prüflogik in eigene Methoden auslagern
  • Normalfall wird explizit

109
Separate Query from Modifier (1)
  • Eine Methode führt eine Abfrage durch und ändert
    gleichzeitig den Zustand des Objekts.
  • Aufspalten in reine Abfrage und Modifikation
  • Reine Abfrage ist vielseitig einsetzbar und
    leicht zu verstehen
  • Optimieren allenfalls später
  • Multithreading / Remote Sonderfälle

110
Separate Query from Modifier (2)
  • Konkrete Schritte
  • Die reine Abfrage als eigene Methode bauen
  • In der ursprünglichen Methode das Ergebnis der
    Abfrage zurückgeben
  • Compilieren und testen
  • In Aufrufen die Abfrage in eigenen Aufruf vor die
    alte Methode setzen
  • Rückgabe der alten Methode entfernen

111
Parameterize Method
  • Mehrere Methoden tun das Gleiche mit
    unterschiedlichen fest verdrahteten Werten.
  • Zusammenführen in eine einzige Methode mit
    Parameter
  • Vermeidet Code-Duplizierung

112
Replace Parameter with Explicit Methods
  • Ein Methode macht völlig verschiedene Dinge
    abhängig vom Wert eines Parameters.
  • In mehrere Methoden mit sprechenden Namen zerlegen

113
Preserve Whole Object
  • Eine Methode bekommt mehrere Attribute des
    gleichen Objekts als Parameter.
  • Besser das ganze Objekt als Parameter
    hineinreichen
  • Außer man will bewusst entkoppeln

114
Replace Parameter with Method
  • Eine Methode bekommt einen Parameter, den sie
    auch selbst ermitteln könnte.
  • Parameter ermitteln und aus der Signatur
    entfernen
  • Durch Methode von this oder von einem anderen
    Parameter

115
Introduce Parameter Object (1)
  • Mehrere Parameter bilden eine natürliche Einheit.
  • Zu einem neuen Typ zusammenfassen
  • Wertsemantik
  • Typsicher, besser lesbar

116
Introduce Parameter Object (2)
  • Konkrete Schritte
  • Neue Klasse leer anlegen
  • Die Parameter als Attribute hinzufügen. Dabei die
    Werte immutable machen
  • Den jeweiligen Parameter aus dem Aufruf
    entfernen. Compilieren und Testen
  • Funktionalität in die neue Klasse extrahieren

117
Remove Setting Method
  • Ein Feld wird nur bei der Erzeugung gesetzt und
    anschließend nicht mehr geändert.
  • Ggf. Konstruktor einführen
  • Set-Methode entfernen
  • Feld final machen

118
Encapsulate Downcast
  • Eine Methode liefert eine Referenz, die erst nach
    Downcast verwendbar ist (z.B. ein Element einer
    Collection).
  • Downcast in der Methode durchführen und den
    richtigen Typ zurückliefern
  • Erhöht die Übersichtlichkeit und Typsicherheit

119
Pull Up Method
  • Unterklassen haben Methoden mit dem gleichen
    Ergebnis.
  • Methoden in die Basisklasse verschieben
  • Code-Duplizierung vermeiden
  • Eventuell unterschiedliche Algorithmen

120
Push Down Method
  • Eine Methode der Basisklasse wird nur von einer
    Unterklasse verwendet.
  • Die Methode in diese Unterklasse verschieben
  • Macht die Basisklasse einfacher
  • Dokumentiert die Abhängigkeiten

121
Extract Superclass
  • Mehrere Klassen haben teilweise die gleichen
    Methoden.
  • Gemeinsamkeiten in eine Basisklasse ziehen
  • Dokumentiert Beziehung zwischen den Klassen
  • Öffnet den Blick für Verwendung dieser neuen
    Abstraktion

122
Form Template Method (1)
  • Unterklassen haben Methoden, die ähnliche
    Schritte in der gleichen Reihenfolge durchführen.
  • Methoden extrahieren für Schritte, die von einer
    neuen Methode der Basisklasse aufgerufen werden
  • Vermeidet Code-Duplizierung, dokumentiert
    Beziehungen

123
Form Template Method (2)
  • Konkrete Schritte
  • Methoden zerlegen
  • Methodensignaturen vereinheitlichen
  • Jeweils compilieren und testen
  • Ursprüngliche Methode in Basisklasse ziehen

124
Replace Inheritance with Delegation
  • Eine Unterklasse will nur einen Teil der
    Schnittstelle der Basisklasse haben.
  • Besser Aufrufe an eine Instanz der Basisklasse
    durchreichen
  • Klarere Beziehungen Vererbung legt Polymorphie
    nahe

125
Der Code ist das Design
  • Alle hier präsentierten Refactorings wollen das
    Design im Quelltext klarer ausdrücken.
  • Namen sind sehr wichtig
  • Klarheit und Einfachheit
  • Compilerunterstützung
  • Diese Ziele sind wichtiger als das Verwenden
    konkreter Refactorings!

126
Übersicht
  • Einführung
  • Das Umfeld für Refactoring
  • Code Smells als Wegweiser
  • Automatisierte Tests mit JUnit
  • Konkrete Refactorings
  • ? Beispiel
  • Toolunterstützung

127
Beispiel
  • Ein praktisches Beispiel der Refactorings
  • Der Quelltext ist im Internet verfügbar
    www.haase-consulting.com/download/oop2002

128
Übersicht
  • Einführung
  • Das Umfeld für Refactoring
  • Code Smells als Wegweiser
  • Automatisierte Tests mit JUnit
  • Konkrete Refactorings
  • Beispiel
  • ? Toolunterstützung

129
Toolunterstütztes Refactoring
  • Die Durchführung des Refactoring lässt sich
    weitgehend automatisieren.
  • Schutz vor Flüchtigkeitsfehlern
  • Mehr als Suchen und Ersetzen
  • Plausibilitätsprüfungen

130
Kriterien für Toolauswahl
  • Folgende Punkte stellen Kriterien für die Auswahl
    eines Refactoring-Tools dar
  • Zuverlässigkeit
  • Integration mit IDE
  • Auf dem Parse-Baum operieren (Extract Method
    als Indiz)
  • Geschwindigkeit

131
Refactoring-Tools
  • Hier eine Auswahl von aktuellen Refactoring-Tools
    für Java
  • Idea (www.intellij.com)
  • Xrefactory (xref-tech.com/speller)
  • Eclipse (www.eclipse.org)
  • ...

132
Toolunterstützung praktisch
  • Demonstration für toolgestütztes Refactoring
  • So einfach kann Refactoring in der Praxis sein.

133
Literatur
  • Folgende Quellen sind gute Startpunktefür eine
    Vertiefung
  • Refactoring, Martin Fowler
  • www.refactoring.org
  • www.junit.org
  • Extreme Programming Explained, Kent Beck

134
Zusammenfassung
  • Refactoring
  • Das Umfeld von Refactoring
  • Code Smells
  • JUnit
  • Refactoring-Katalog
  • Toolunterstützung
Write a Comment
User Comments (0)
About PowerShow.com