Vorlesung Softwaretechnologie. Wintersemester este 2009 R O O T S. Refactoring. Stand:

Ähnliche Dokumente
Klassen sollten nicht Wissen über die ganze Hierarchie, sondern nur über Nachbarklassen haben. Dies reduziert die Kopplung!

Klassen sollten nicht Wissen über die ganze Hierarchie, sondern nur über Nachbarklassen haben. Dies reduziert die Kopplung!

Refactoring I. Nach Martin Fowler - Refactoring

Refactoring. Dominique Steiner 1 und Monica De Donato 2. dedom1@bfh.ch

Software-Refactoring. 29. Mai 2013

Refactoring. Programmiermethodik. Eva Zangerle Universität Innsbruck

Software-Refactoring. 27. Mai 2015

Vorlesung Software-Reengineering

C++ Teil 2. Sven Groß. 16. Apr IGPM, RWTH Aachen. Sven Groß (IGPM, RWTH Aachen) C++ Teil Apr / 22

Probeklausur: Programmierung WS04/05

Klausur Grundlagen der Programmierung

5. Tutorium zu Programmieren

Beispiele für Ausdrücke. Der imperative Kern. Der imperative Kern. Imperativer Kern - Kontrollstrukturen. Deklarationen mit Initialisierung

Eine Klasse beschreibt Objekte mit gleichen Attributen und Methoden.

Programmieren 2 Java Überblick

Repetitorium Informatik (Java)

7. Objektorientierte Softwareentwicklung/3. Informatik II für Verkehrsingenieure

Theorie zu Übung 8 Implementierung in Java

3 Objektorientierte Konzepte in Java

Algorithmen und Programmierung II

Java Einführung Methoden in Klassen

Kapitel 4: Klassen und Unterklassen

Java Einführung Abstrakte Klassen und Interfaces

5.4 Klassen und Objekte

Programmieren I + II Regeln der Code-Formatierung

Musterlösung Stand: 5. Februar 2009

Klassendefinitionen verstehen

1 Abstrakte Klassen, finale Klassen und Interfaces

Softwaretechnologie - Wintersemester 2012/ Dr. Günter Kniesel

Javakurs für Anfänger

Vorkurs C++ Programmierung

Arbeitsblätter für die Lehrveranstaltung OOP JAVA 1

Programmieren II. Abstrakte Klassen, Interfaces Heusch 13.8, 13.9 Ratz Institut für Angewandte Informatik

Java Kurs für Anfänger Einheit 5 Methoden

Grundzüge der Programmierung. Wiederverwendung VERERBUNG

Refactoring eine Einführung

Objects First With Java A Practical Introduction Using BlueJ. Mehr über Vererbung. Exploring polymorphism 1.0

Programmieren II. Abstrakte Klassen, Interfaces Heusch 13.8, 13.9 Ratz Institut für Angewandte Informatik

Einstieg in die Informatik mit Java

Javadoc. Programmiermethodik. Eva Zangerle Universität Innsbruck

Kapitel 6. Vererbung

Kapitel 8. Programmierkurs. Methoden. 8.1 Methoden

Einstieg in die Informatik mit Java

OOP und Angewandte Mathematik. Eine Einführung in die Anwendung objektorientierter Konzepte in der angewandten Mathematik

Kapitel 6. Vererbung

VIII: Vererbung. Unterklassen einer Klasse. Vererbung von Methoden und Instanzvariablen. Überschreiben von Methoden

Vererbung. Martin Wirsing. Ziele. Vererbung

Statische und Nichtstatische Methoden Properties/ Eigenschaften

Vererbung. Vererbung von Methoden und Instanzvariablen. Vererbung als Realisierung einer is-a Beziehung.

1. Grundzüge der Objektorientierung 2. Methoden, Unterprogramme und Parameter 3. Datenabstraktion 4. Konstruktoren 5. Vordefinierte Klassen

Java Einführung Methoden. Kapitel 6

Refactoring. Vortrag im Rahmen des Softwareprojekts: Übersetzerbau. Referenten: Vivienne Severa Alpin Mete Sahin Florian Mercks. Datum:

Wiederholung zur Vorlesung Programmieren

Wiederholung Wozu Methoden? Methoden Schreiben Methoden Benutzen Rekursion?! Methoden. Javakurs 2012, 3. Vorlesung

Programmieren in Java

II. Grundlagen der Programmierung. 9. Datenstrukturen. Daten zusammenfassen. In Java (Forts.): In Java:

Grundlagen der Programmierung Prof. H. Mössenböck. 6. Methoden

Kapitel 6. Vererbung

Kapitel 9. Programmierkurs. Attribute von Klassen, Methoden und Variablen. 9.1 Attribute von Klassen, Methoden und Variablen

Klassenentwurf. Wie schreiben wir Klassen, die leicht zu verstehen, wartbar und wiederverwendbar sind? Objektorientierte Programmierung mit Java

6. Globalübung (zu Übungsblatt 8)

Java Einführung Klassendefinitionen

Probeklausur: Programmierung WS04/05

Einführung in die Programmierung

Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 11/12 1. Kapitel 11. Listen. Listen

Nachklausur Programmieren / Algorithmen und Datenstrukturen 1

Elementare Konzepte von

AuD-Tafelübung T-B5b

Java I Vorlesung 6 Referenz-Datentypen

Standardkonstrukte in Java

Software Engineering Klassendiagramme Einführung

Creational Patterns. Seminar Software-Entwurf. Thomas Liro WS 2004/05.

Programmieren II. Innere Klassen. Heusch 10, Ratz 5.2.1, Institut für Angewandte Informatik

am Beispiel von JUnit

Assoziation und Aggregation

Verhindert, dass eine Methode überschrieben wird. public final int holekontostand() {...} public final class Girokonto extends Konto {...

Welche Informatik-Kenntnisse bringen Sie mit?

Prof. W. Henrich Seite 1

Die for -Schleife HEUTE. Schleifen. Arrays. Schleifen in JAVA. while, do reichen aus, um alle iterativen Algorithmen zu beschreiben

JAVA - Methoden

Einstieg in die Informatik mit Java

Schwerpunkte. Verkettete Listen. Verkettete Listen: 7. Verkettete Strukturen: Listen. Überblick und Grundprinzip. Vergleich: Arrays verkettete Listen

Einstieg in die Informatik mit Java

Wiederholung. Jedes Objekt hat seinen eigenen Zustand/seine eigenen Variablen (gilt auch für mehrere Objekte, die zur gleichen Klasse gehören).

Java Vererbung. Inhalt

JAVA - Methoden - Rekursion

Vererbung & Schnittstellen in C#

5.5.8 Öffentliche und private Eigenschaften

Einführung in die Programmierung mit Java

5. Abstrakte Klassen. Beispiel (3) Abstrakte Klasse. Beispiel (2) Angenommen, wir wollen die folgende Klassenhierarchie implementieren:

Drei-Schichten-Architektur. Informatik B - Objektorientierte Programmierung in Java. Vorlesung 16: 3-Schichten-Architektur 1 Fachkonzept - GUI

3 Objektorientierte Konzepte in Java

Klassen mit Instanzmethoden

Objektorientierte Programmierung

Neue Features in C# 2.0

Objektorientierte Programmierung

Programmierkurs C++ Abstrakte Klassen und Methoden

Interaktionen zwischen Objekten durch Senden von Nachrichten und Reagieren auf empfangene Nachrichten

7. Schnittstellen Grundlagen zu Schnittstellen. 7. Schnittstellen

Software-Restrukturierung

Transkript:

Vorlesung Softwaretechnologie Wintersemester este 2009 R O O T S Kapitel 0 Refactoring Stand: 28.02.2009

"Refactoring" Einstiegs-Beispiel Refactoring: Schritt für Schritt Beispiel: Extract Method Indikationen für Refactoring ("Bad Smells in Code") Refactoring-Überblick 2000-2009 Dr. G. Kniesel Vorlesung Softwaretechnologie (SWT) Seite 0-2 R O O T S

Was ist überhaupt Refactoring? Refactoring (noun): a change made to the internal structure of software to make it easier to understand and cheaper to modify without changing its observable behavior. Refactor (verb): to restructure software by applying a series of refactorings. Definition Systematische Umstrukturierung des Codes ohne das Verhalten nach außen zu ändern Nutzen bessere Lesbarkeit, Verständlichkeit besseres Design bessere Wartbarkeit und Wiederverwendbarkeit 2000-2009 Dr. G. Kniesel Vorlesung Softwaretechnologie (SWT) Seite 0-3 R O O T S

Warum Refactoring anwenden? Refactoring verbessert das Design der Software Oft geänderte Software verliert mit der Zeit ihre Struktur. Redundanter Code erfordert vielfache Änderungen. Extraktion gemeinsamer Teile ermöglicht jede Änderung an genau einer Stelle durchzuführen. Refactoring macht die Software verständlicher Verständlichkeit für den Programmierer, der vielleicht später am Programm Erweiterungen vornimmt Wenn man sich in ein Programm einarbeitet, kann man es besser verstehen, wenn man es restrukturiert. Refactoring hilft Bugs zu finden Im Prozess des Refactorings erwirbt man ein tiefes Verständnis für den Code. Man kann Bugs leichter finden. Refactoring macht das Programmieren schneller Wenn der Code ein gutes Design hat, gut verständlich ist und daher auch wenig Bugs hat, kann man schneller programmieren. 2000-2009 Dr. G. Kniesel Vorlesung Softwaretechnologie (SWT) Seite 0-4 R O O T S

Vorlesung Softwaretechnologie Wintersemester este 2009 R O O T S Refactoring: ein Anwendungsbeispiel

Anwendungsbeispiel: Videofilm-Verleih Videos können im Laufe der Zeit zu verschiedenen Preiskategorien gehören (Normal, Jugend, Neuerscheinung). Jede Preiskategorie beinhaltet eine andere Preisberechnung. Jede Ausleihe führt zur Gutschrift von Bonuspunkten, die am Jahresende abgerechnet werden. Der Umfang der Gutschrift hängt ebenfalls von der Preiskategorie ab. Für jeden Kunden soll es möglich sein, eine Rechnung für die ausgeliehenen Videos auszudrucken Titel und Preis eines jeden ausgeliehenen Videos Summe der Ausleihgebühren Summe der Bonuspunkte 2000-2009 Dr. G. Kniesel Vorlesung Softwaretechnologie (SWT) Seite 0-6 R O O T S

Erster Versuch Jeder Film (Movie) kennt seinen Titel und seine Preiskategorie Jede Ausleihe (Rental) kennt den ausgeliehenen Film und die Leihdauer Jeder Kunde (Customer) kennt die Menge seiner aktuellen Ausleihen... kann den Text der dafür fälligen Rechnung selbst ermitteln (Methode invoice()) Customer invoice() : String Rental daysrented:int Movie title:string il i pricecode:int 2000-2009 Dr. G. Kniesel Vorlesung Softwaretechnologie (SWT) Seite 0-7 R O O T S

Nächster Versuch Jeder Film (Movie) kennt seinen Titel und seine Preiskategorie Jede Ausleihe (Rental) kennt den ausgeliehenen Film und die Leihdauer Jeder Kunde (Customer) kennt die Menge seiner aktuellen Ausleihen... kann den Text der dafür fälligen Rechnung selbst ermitteln (Methode invoice()) Instanz-Variablen sind privat, auf ihre Werte wird via Methoden zugegriffen Customer Rental Movie invoice() : String getdaysrented():int getmovie():movie gettitle():string :int setpricecode(int) 2000-2009 Dr. G. Kniesel Vorlesung Softwaretechnologie (SWT) Seite 0-3 R O O T S

Movie Customer invoice() Rental getdaysrented() getmovie() Movie setpricecode() gettitle() public class Movie { public static final int CHILDRENS = 2; public static final int REGULAR = 0; public static final int NEW_RELEASE =; private String _title; private int _pricecode; public Movie(String title, int pricecode) { _title = title; _pricecode = pricecode; public int { return _pricecode; public void setpricecode(int arg) { _pricecode = arg; public String gettitle() { return _title; 2000-2009 Dr. G. Kniesel Vorlesung Softwaretechnologie (SWT) Seite 0-4 R O O T S

Rental Customer invoice() Rental getdaysrented() getmovie() Movie setpricecode() gettitle() class Rental { private Movie _movie; private int _daysrented; public Rental(Movie movie, int daysrented) { _movie = movie; _daysrented = daysrented; public int getdaysrented() { return _daysrented; public Movie getmovie() { return _movie; 2000-2009 Dr. G. Kniesel Vorlesung Softwaretechnologie (SWT) Seite 0-5 R O O T S

Customer Customer invoice() Rental getdaysrented() getmovie() Movie setpricecode() gettitle() class Customer { private String _name; private Vector _rentals = new Vector(); public Customer(String name) { _name = name; public void addrental(rental arg) { _rentals.addelement(arg); public String getname() { return _name; Auch wenn der Typ von _rentals sich mal ändert, bleibt für Clients von Customer das Hinzufügen eines neuen Ausleihobjekts gleich. 2000-2009 Dr. G. Kniesel Vorlesung Softwaretechnologie (SWT) Seite 0-6 R O O T S

Die invoice()- Methode (Teil ) Customer invoice() Rental getdaysrented() getmovie() Movie setpricecode() gettitle() public String invoice() { double totalamount = 0; int bonuspoints = 0; Enumeration rentals = _rentals.elements(); String result = Rental Record for +getname()+ \n ; while (rentals.hasmoreelements()) { double thisamount = 0; Rental each = (Rental) rentals.nextelement(); // determine amounts for each line switch (each.getmovie().) { case Movie.REGULAR: thisamount += 2; if (each.getdaysrented() > 2) thisamount += (each.getdaysrented()-2).5; break; case Movie.NEW_RELEASE: thisamount += each.getdaysrented()3; break; case Movie.CHILDRENS: thisamount +=,5; if (each.getdaysrented() ays e ted() > 3) thisamount += (each.getdaysrented()-3).5; break;

Die invoice()- Methode (Teil 2) Customer invoice() Rental getdaysrented() getmovie() Movie setpricecode() gettitle() // add frequent renter points bonuspoints ++; // add bonus for a two day new release rental if ((each.getmovie(). == Movie.NEW_RELEASE) && each.getdaysrented()>) bonuspoints ++; // show figures for this rental result += \t + each.getmovie().gettitle() + \t + String.valueOf(thisAmount) + \n ; totalamount += thisamount; // add footer lines result += Amount owed is + String.valueOf(totalAmount) + \n ; result += You earned + String.valueOf(bonusPoints) + frequent renter points ; return result; 2000-2009 Dr. G. Kniesel Vorlesung Softwaretechnologie (SWT) Seite 0-8 R O O T S

Interaktionen der invoice() Methode invoice() acustomer arental amovie [for all rentals] getmovie() Kommentare? getdaysrented() Customer Rental Movie invoice() : String getdaysrented():int getmovie():movie :int setpricecode(int) gettitle():string 2000-2009 Dr. G. Kniesel Vorlesung Softwaretechnologie (SWT) Seite 0-9 R O O T S

Schritte zur Besserung Methoden aufteilen Customer invoice() Rental getdaysrented() getmovie() Movie setpricecode() gettitle() z.b. Beitrags- und Bonuspunktberechnung aus invoice() extrahieren leichter verständlich Teile eventuell in anderen Kontexten wieder verwendbar Teilmethoden in passendere Klassen verlagern Methoden näher an "ihre" Daten (z.b. Beitrags- und Bonuspunktberechnung) weniger Abhängigkeiten zwischen Klassen Temporäre Variablen eliminieren Vereinfachung Auslagerung von Methoden erleichtern (z.b. Summierung der Bonuspunkte) Ersetzung von Fallunterscheidungen (switch-statement) durch Nachrichten kleinere, klarere Methoden Erweiterbarkeit um zusätzliche Fälle ohne Änderung der clients einer Klasse z.b. zusätzliche Preiskategorien einführen ohne Änderung von invoice() 2000-2009 Dr. G. Kniesel Vorlesung Softwaretechnologie (SWT) Seite 0-2 R O O T S

Extrahieren der Betragsberechnung amountfor(rental) Customer invoice() Rental getdaysrented() getmovie() Movie setpricecode() gettitle() public String invoice() { double totalamount = 0; int bonuspoints = 0; Enumeration rentals = _rentals.elements(); String result = Rental Record for +getname()+ \n ; while (rentals.hasmoreelements()) { double thisamount = 0; Rental each = (Rental) rentals.nextelement(); // determine amounts for each rental switch (each.getmovie().) { case Movie.REGULAR: thisamount += 2; if (each.getdaysrented() ays e ted() > 2) thisamount += (each.getdaysrented()-2).5; break; case Movie.NEW_RELEASE: thisamount += each.getdaysrented()3; break; case Movie.CHILDRENS: thisamount +=.5; if (each.getdaysrented() > 3) thisamount += (each.getdaysrented()-3).5; break;

Extrahieren der Betragsberechnung amountfor(rental) Customer invoice() Rental getdaysrented() getmovie() Movie setpricecode() gettitle() public String invoice() { double totalamount = 0; int bonuspoints = 0; Enumeration rentals = _rentals.elements(); String result = Rental Record for +getname()+ \n ; while (rentals.hasmoreelements()) { Rental each = (Rental) rentals.nextelement(); private double amountfor(rental each) { double thisamount t = double thisamount = 0; amountfor(each); switch (each.getmovie().) { case Movie.REGULAR: thisamount += 2; if (each.getdaysrented() () > 2) thisamount += (each.getdaysrented()-2).5; break; case Movie.NEW_RELEASE: thisamount += each.getdaysrented()3; break; case Movie.CHILDRENS: thisamount +=.5; if (each.getdaysrented() > 3) thisamount += (each.getdaysrented()-3).5; break; return thisamount;

Ändern lokaler Variablenamen: Vorher Customer invoice() Rental getdaysrented() getmovie() Movie setpricecode() gettitle() Im neuen Kontext sinnvolle Namen: each arental thisamount result class Customer {... private double amountfor(rental each ) { double thisamount = 0; switch ( each.getmovie().) { case Movie.REGULAR: thisamount += 2; if ( each.getdaysrented() > 2) thisamount += ( each.getdaysrented()-2).5; break; case Movie.NEW_RELEASE: thisamount += each.getdaysrented()3; break; case Movie.CHILDRENS: thisamount +=.5; if ( each.getdaysrented() > 3) thisamount += ( each.getdaysrented()-3).5; break; return thisamount t ;

Ändern lokaler Variablennamen: Nachher Customer invoice() Rental getdaysrented() getmovie() Movie setpricecode() gettitle() Im neuen Kontext sinnvolle Namen: each arental thisamount result class Customer {... private double amountfor(rental arental) { double result = 0; switch (arental.getmovie().) { case Movie.REGULAR: result += 2; if (arental.getdaysrented() > 2) result += (arental.getdaysrented()-2).5; break; case Movie.NEW_RELEASE: result += arental.getdaysrented()3; break; case Movie.CHILDRENS: result +=.5; if (arental.getdaysrented() > 3) result += (arental.getdaysrented()-3).5; break; return result;

Beitragsberechnung nach "Rental" verlagern: Vorher Customer invoice() Rental getdaysrented() getmovie() Movie setpricecode() gettitle() class Customer {... private double amountfor(rental arental) { double result = 0; switch (arental.getmovie().) { case Movie.REGULAR: result += 2; if (arental.getdaysrented() > 2) result += (arental.getdaysrented()-2).5; break; case Movie.NEW_RELEASE: result += arental.getdaysrented()3; break; case Movie.CHILDRENS: result +=.5; if (arental.getdaysrented() > 3) result += (arental.getdaysrented()-3).5; break; return result;

Beitragsberechnung nach "Rental" verlagern: Nachher Customer invoice() Rental getdaysrented() getmovie() charge() class Customer {... Private private double amountfor(rental arental) { Weiterleitungsmethode return arental.charge(); kann eliminiert werden Movie setpricecode() gettitle() Umbenennungen: amountfor(...) charge() arental this (weggelassen) class Rental {... private double charge( ) { double result = 0; switch ( getmovie().) { case Movie.REGULAR: result += 2; if ( getdaysrented() > 2) result += ( getdaysrented()-2).5; break; case Movie.NEW_RELEASE: result += getdaysrented()3; break; case Movie.CHILDRENS: result +=.5; if ( getdaysrented() > 3) result += ( getdaysrented()-3).5; break; return result;

Aufrufstelle anpassen: Vorher Customer invoice() Rental getdaysrented() getmovie() charge() Movie setpricecode() gettitle() public String invoice() { double totalamount = 0; int bonuspoints = 0; Enumeration rentals = _rentals.elements(); String result = Rental Record for +getname()+ \n ; while (rentals.hasmoreelements()) { Rental each = (Rental) rentals.nextelement(); double thisamount= amountfor(each); // add frequent renter points bonuspoints ++; // add bonus for a two day new release rental if ((each.getmovie(). == Movie.NEW_RELEASE) && each.getdaysrented()>) bonuspoints ++; // show figures for this rental result += \t + each.getmovie().gettitle()+ \t + String.valueOf(thisAmount)+ \n ; totalamount += thisamount; // add footer lines result += Amount owed is + String.valueOf(totalAmount) + \n ; result += You earned + String.valueOf(bonusPoints) + frequent renter points ; return result; 2000-2009 Dr. G. Kniesel Vorlesung Softwaretechnologie (SWT) Seite 0-28 R O O T S

Aufrufstelle anpassen: Nachher Customer invoice() Rental getdaysrented() getmovie() charge() Movie setpricecode() gettitle() public String invoice() { double totalamount = 0; int bonuspoints = 0; Enumeration rentals = _rentals.elements(); String result = Rental Record for +getname()+ \n ; while (rentals.hasmoreelements()) { Rental each = (Rental) rentals.nextelement(); double thisamount= each.charge(); // add frequent renter points bonuspoints ++; // add bonus for a two day new release rental if ((each.getmovie(). == Movie.NEW_RELEASE) && each.getdaysrented()>) bonuspoints ++; // show figures for this rental result += \t + each.getmovie().gettitle()+ \t + String.valueOf(thisAmount)+ \n ; totalamount += thisamount; // add footer lines result += Amount owed is + String.valueOf(totalAmount) + \n ; result += You earned + String.valueOf(bonusPoints) + frequent renter points ; return result; 2000-2009 Dr. G. Kniesel Vorlesung Softwaretechnologie (SWT) Seite 0-29 R O O T S

Bonuspunkt-Berechnung extrahieren Customer invoice() Rental getdaysrented() getmovie() charge() Movie setpricecode() gettitle() public String invoice() { double totalamount = 0; int bonuspoints = 0; Enumeration rentals = _rentals.elements(); String result = Rental Record for +getname()+ \n ; while (rentals.hasmoreelements()) { Rental each = (Rental) rentals.nextelement(); double thisamount= each.charge(); // add frequent renter points bonuspoints ++; // add bonus for a two day new release rental if ((each.getmovie(). == Movie.NEW_RELEASE) && each.getdaysrented()>) bonuspoints++; // show figures for this rental result += \t + each.getmovie().gettitle()+ \t + String.valueOf(thisAmount)+ \n ; totalamount += thisamount; // add footer lines result += Amount owed is + String.valueOf(totalAmount) + \n ; result += You earned + String.valueOf(bonusPoints) + frequent renter points ; return result; 2000-2009 Dr. G. Kniesel Vorlesung Softwaretechnologie (SWT) Seite 0-30 R O O T S

Bonuspunkt-Berechnung extrahieren Customer invoice() Rental getdaysrented() getmovie() charge() bonuspoints() Movie setpricecode() gettitle() public String invoice() { double totalamount = 0; int bonuspoints = 0; Enumeration rentals = _rentals.elements(); String result = Rental Record for +getname()+ \n ; while (rentals.hasmoreelements()) { Rental each = (Rental) rentals.nextelement(); double thisamount= each.charge(); bonuspoints += each.bonuspoints(); class Rental... int bonuspoints() { if ((getmovie().==movie.new_release) // show figures for this rental && getdaysrented() > ) result += \t + each.getmovie().gettitle()+ return 2; \t + String.valueOf(thisAmount)+ else \n ; totalamount += thisamount; return ; // add footer lines result += Amount owed is + String.valueOf(totalAmount) + \n ; result += You earned + String.valueOf(bonusPoints) + frequent renter points ; return result; 2000-2009 Dr. G. Kniesel Vorlesung Softwaretechnologie (SWT) Seite 0-3 R O O T S

Kosten- und Bonuspunkt-Berechnung extrahieren: Vorher invoice() acustomer arental amovie [for all rentals] getmovie() getdaysrented() Customer invoice() Rental daysrented:int getmovie() getdaysrented() Movie pricecode:int 2000-2009 Dr. G. Kniesel Vorlesung Softwaretechnologie (SWT) Seite 0-32 R O O T S

Kosten- und Bonuspunkt-Berechnung extrahieren: Nachher invoice() acustomer arental amovie [for all rentals] charge() bonuspoints() Customer invoice() Rental daysrented:int getmovie() getdaysrented() charge() bonuspoints() Movie pricecode:int

Schritte zur Besserung Customer invoice() Rental getdaysrented() getmovie() charge() bonuspoints() Movie setpricecode() gettitle() invoice()-methode i aufteilen Teilmethoden in passendere Klassen verlagern Temporäre Variablen eliminieren Vereinfachung Auslagerung von Methoden erleichtern (z.b. Summierung der Bonuspunkte) Ersetzung von Fallunterscheidungen durch Nachrichten 2000-2009 Dr. G. Kniesel Vorlesung Softwaretechnologie (SWT) Seite 0-34 R O O T S

Temporäre Variablen eliminieren: thisamount Customer invoice() Rental getdaysrented() getmovie() charge() bonuspoints() Movie setpricecode() gettitle() public String invoice() { double totalamount = 0; int bonuspoints = 0; Enumeration rentals = _rentals.elements(); String result = Rental Record for +getname()+ \n ; while (rentals.hasmoreelements()) { Rental each = (Rental) rentals.nextelement(); double thisamount = each.charge(); bonuspoints += each.bonuspoints(); // show figures for this rental result += \t + each.getmovie().gettitle()+ \t + String.valueOf(thisAmount)+ \n ; totalamount += thisamount; // add footer lines result += Amount owed is + String.valueOf(totalAmount) + \n ; result += You earned + String.valueOf(bonusPoints) + frequent renter points ; return result; 2000-2009 Dr. G. Kniesel Vorlesung Softwaretechnologie (SWT) Seite 0-35 R O O T S

Temporäre Variablen eliminieren: thisamount Customer invoice() Rental getdaysrented() getmovie() charge() bonuspoints() Movie setpricecode() gettitle() public String invoice() { double totalamount = 0; int bonuspoints = 0; Enumeration rentals = _rentals.elements(); String result = Rental Record for +getname()+ \n ; while (rentals.hasmoreelements()) { Rental each = (Rental) rentals.nextelement(); bonuspoints += each.bonuspoints(); // show figures for this rental result += \t + each.getmovie().gettitle()+ \t + String.valueOf(each.charge())+ \n ; totalamount += each.charge(); // add footer lines result += Amount owed is + String.valueOf(totalAmount) + \n ; result += You earned + String.valueOf(bonusPoints) + frequent renter points ; return result; 2000-2009 Dr. G. Kniesel Vorlesung Softwaretechnologie (SWT) Seite 0-36 R O O T S

Schleifenübergreifende temporäre Variablen eliminieren Customer invoice() Rental getdaysrented() getmovie() charge() bonuspoints() Movie setpricecode() gettitle() public String invoice() { double totalamount = 0; int bonuspoints = 0; Enumeration rentals = _rentals.elements(); String result = Rental Record for +getname()+ \n ; while (rentals.hasmoreelements()) { Rental each = (Rental) rentals.nextelement(); bonuspoints += each.bonuspoints(); // show figures for this rental result += \t + each.getmovie().gettitle()+ \t + String.valueOf(each.charge())+ \n ; totalamount += each.charge(); // add footer lines result += Amount owed is + String.valueOf(totalAmount) + \n ; result += You earned + String.valueOf(bonusPoints) + frequent renter points ; return result; 2000-2009 Dr. G. Kniesel Vorlesung Softwaretechnologie (SWT) Seite 0-37 R O O T S

Schleifenübergreifende temporäre Variablen eliminieren Customer invoice() Rental getdaysrented() getmovie() charge() bonuspoints() Movie setpricecode() gettitle() public String invoice() { double totalamount = 0; int bonuspoints = 0; Enumeration rentals = _rentals.elements(); String result = Rental Record for +getname()+ \n ; while (rentals.hasmoreelements()) { Rental each = (Rental) rentals.nextelement(); bonuspoints += each.bonuspoints(); // show figures for this rental result += \t + each.getmovie().gettitle()+ \t + String.valueOf(each.charge())+ \n ; totalamount += each.charge(); // add footer lines result += Amount owed is + String.valueOf(totalAmount) + \n ; result += You earned + String.valueOf(bonusPoints) + frequent renter points ; return result; private double totalcharge() { double result = 0; Enumeration rentals = _rentals.elements(); while (rentals.hasmoreelements()){ Ersatz für totalamount Rental each = (Rental) rentals.nextelement(); result += each.charge(); h return result;

Schleifenübergreifende temporäre Variablen eliminieren (2) Customer invoice() Rental getdaysrented() getmovie() charge() bonuspoints() Movie setpricecode() gettitle() public String invoice() { int bonuspoints = 0; Enumeration rentals = _rentals.elements(); String result = Rental Record for +getname()+ \n ; while (rentals.hasmoreelements()) { Rental each = (Rental) rentals.nextelement(); bonuspoints += each.bonuspoints(); // show figures for this rental result += \t + each.getmovie().gettitle()+ \t + String.valueOf(each.charge())+ \n ; // add footer lines result += Amount owed is + String.valueOf(totalCharge()) + \n ; result += You earned + String.valueOf(bonusPoints) + frequent renter points ; private double totalcharge() { return result; double result = 0; Enumeration rentals = _rentals.elements(); while (rentals.hasmoreelements()){ Ersatz für totalamount Rental each = (Rental) rentals.nextelement(); result += each.charge(); h return result;

Schleifenübergreifende temporäre Variablen eliminieren (3) Customer invoice() Rental getdaysrented() getmovie() charge() bonuspoints() Movie setpricecode() gettitle() public String invoice() { Enumeration rentals = _rentals.elements(); String result = Rental Record for +getname()+ \n ; while (rentals.hasmoreelements()) { Rental each = (Rental) rentals.nextelement(); // show figures for this rental result += \t + each.getmovie().gettitle()+ \t + String.valueOf(each.charge())+ \n ; // add footer lines result += Amount owed is + String.valueOf(totalCharge()) + \n ; result += You earned + String.valueOf(totalBonusPoints()) + frequent renter points ; private double totalbonuspoints() { return result; double result = 0; Enumeration rentals = _rentals.elements(); while (rentals.hasmoreelements()){ Ersatz für bonuspoints Rental each = (Rental) rentals.nextelement(); result += each.bonuspoints(); return result;

Endzustand der invoice()-methode Customer invoice() Rental getdaysrented() getmovie() charge() bonuspoints() Movie setpricecode() gettitle() public String invoice() { // add header line String result = Rental t l Record for + getname() + \n ; // show figures for each rental Enumeration rentals = _rentals.elements(); while (rentals.hasmoreelements()) { Rental each = (Rental) rentals.nextelement(); result += \t + each.getmovie().gettitle() + \t + String.valueOf(each.charge()) + \n ; // add footer lines result += Amount owed is + String.valueOf(totalCharge()) + \n ; result += You earned + String.valueOf(totalBonusPoints()) + frequent renter points ; return result; 2000-2009 Dr. G. Kniesel Vorlesung Softwaretechnologie (SWT) Seite 0-4 R O O T S

Einfügen von invoiceashtml() Customer invoice() invoiceashtml() Rental getdaysrented() getmovie() charge() bonuspoints() Movie setpricecode() gettitle() public String invoiceashtml() { // add header lines String result = <H>Rentals t l for <EM> + getname() + </EM></H><P>\n ; // show figures for each rental Enumeration rentals = _rentals.elements(); while (rentals.hasmoreelements()) { Rental each = (Rental) rentals.nextelement(); result += each.getmovie().gettitle() + :: + String.valueOf(each.charge()) + <BR>\n ; Die neue Methode reduziert sich auf Methode reduziert sich auf die Details der HTML-Formatierung. Details der HTML-Formatierung. Die Die eigentlichen eigentlichen Berechnungen Berechnungen werden wiederverwendet. werden wiederverwendet. // add footer lines result += <P> You owe <EM> + String.valueOf(totalCharge()) + </EM></P>\n ; result += On this rental you earned <EM> + String.valueOf(totalBonusPoints()) + </EM> frequent renter points<p> ; return result; 2000-2009 Dr. G. Kniesel Vorlesung Softwaretechnologie (SWT) Seite 0-42 R O O T S

Temporäre Variablen durch Nachrichten ersetzen: Vorher invoice() acustomer arental amovie [for all rentals] charge() bonuspoints() Customer invoice() Rental daysrented:int getmovie() getdaysrented() charge() bonuspoints() Movie pricecode:int

Temporäre Variablen durch Nachrichten ersetzen: Nachher invoice() acustomer arental amovie totalcharge() [for all rentals] charge() totalbonuspoints() [for all rentals] bonuspoints() Customer invoice() invoiceashtml() totalcharge() totalbonuspoints() Rental daysrented:int getmovie() getdaysrented() charge() bonuspoints() Movie pricecode:int

Schritte zur Besserung Customer invoice() Rental getdaysrented() getmovie() charge() bonuspoints() Movie setpricecode() gettitle() invoice()-methode aufteilen Teilmethoden in passendere Klassen verlagern Temporäre Variablen eliminieren i i Ersetzung der preiscodeabhängigen Fallunterscheidung durch Nachricht Verlagern der Methode Anwenden des Strategy Patterns 2000-2009 Dr. G. Kniesel Vorlesung Softwaretechnologie (SWT) Seite 0-45 R O O T S

charge()-methode aus Rental nach Movie Customer Rental Movie verlagern: invoice() Vorher getdaysrented() getmovie() charge() bonuspoints() setpricecode() gettitle() charge() class Rental... public double charge() { double result = 0; switch (getmovie().) { case Movie.REGULAR: result += 2; if (getdaysrented() > 2) result += (getdaysrented()-2).5; break; case Movie.NEW_RELEASE: result +=getdaysrented()3; break; case Movie.CHILDRENS: result +=.5; if (getdaysrented() > 3) result += (getdaysrented()-3).5; break; 2000-2009 Dr. G. Kniesel Vorlesung Softwaretechnologie (SWT) Seite 0-46 R O O T S

charge()-methode aus Rental nach Movie Customer Rental Movie verlagern: invoice() Nachher getdaysrented() getmovie() charge() bonuspoints() setpricecode() gettitle() charge() class Movie... public double charge(int daysrented) { double result = 0; switch ( ) { case Movie.REGULAR: result += 2; if ( daysrented > 2) result += ( daysrented -2).5; break; case Movie.NEW_RELEASE: result += daysrented 3; break; case Movie.CHILDRENS: result +=.5; if ( daysrented > 3) result += ( daysrented -3).5; break; class Rental... public double charge() { return _movie.charge(_daysrented);

bonuspoints()-methode aus Rental nach Customer Rental Movie verlagern invoice() class Movie... public int bonuspoints(int daysrented) { if ( (this.==new_release) && daysrented>) return 2; else return ; getdaysrented() getmovie() charge() bonuspoints() Movie setpricecode() gettitle() charge() bonuspoints() class Rental... public int bonuspoints() { if ((getmovie().==movie.new_release) && getdaysrented()>) return 2; else return ; class Rental... public int bonuspoints() { return _movie.bonuspoints(_daysrented);

Schritte zur Besserung Customer invoice() Rental getdaysrented() getmovie() charge() bonuspoints() Movie setpricecode() gettitle() invoice()-methode aufteilen Teilmethoden in passendere Klassen verlagern Temporäre Variablen eliminieren i i Ersetzung der preiscodeabhängigen Fallunterscheidung durch Nachricht Verlagern der Methode Anwenden des Strategy Patterns

Polymorphismus via Vererbung Hier nicht anwendbar: ein Film hätte immer eine fixe Preiskategorie Customer totalcharge() totalbonuspoints() invoice() invoiceashtml() Rental daysrented:int charge() bonuspoints () Movie pricecode:int setpricecode() charge(days:int) bonuspoints(days:int) ( y ) ChildrensPrice NewReleasePrice RegularPrice charge(days:int) charge(days:int) bonuspoints(days:int) charge(days:int) 2000-2009 Dr. G. Kniesel Vorlesung Softwaretechnologie (SWT) Seite 0-5 R O O T S

Polymorphismus via State Pattern Customer Rental daysrented:int Movie pricecode:int Price pricecode:int invoice() totalcharge() totalbonuspoints() invoiceashtml() getdaysrented():int getmovie():movie charge() bonuspoints () setpricecode() charge(days:int) bonuspoints(days:int) ( y ) charge(days:int) bonuspoints(days:int) ( y ) ChildrensPrice NewReleasePrice RegularPrice charge(days:int) charge(days:int) bonuspoints(days:int) charge(days:int) 2000-2009 Dr. G. Kniesel Vorlesung Softwaretechnologie (SWT) Seite 0-52 R O O T S

Polymorphismus via State Pattern Schritte. Klassen Price,..., RegularPrice erzeugen 2. Darin -Methoden implementieren 3. Ersetzung von Preis-Code durch Preis-Objekt (in Movie) setpricecode(int) getpricecode Konstruktor 4. charge() und bonuspoints() von Movie nach Price verlagern 5. Fallunterscheidungen durch Polymorphimus ersetzen jeden Fall der charge() Methode aus Price in die charge()-methode einer Unterklasse auslagern analog für bonuspoints() Movie pricecode:int setpricecode() charge(days:int) bonuspoints(days:int) NewReleasePrice charge(days:int) bonuspoints(days:int) Price pricecode:int charge(days:int) ( y ) bonuspoints(days:int) ( y ) RegularPrice charge(days:int)

Schritt -3: Ersetzung von Preis-Code durch Preis-Objekt class Movie {... private int _pricecode; class Movie... private Price _price; public Movie(String name, int pricecode) { _name = name; _pricecode = pricecode; public int { 3 return _pricecode; public void setpricecode(int arg) { _pricecode = arg; +2 abstract class Price { public abstract int ; class RegularPrice extends Price { public int { return Movie.REGULAR; class ChildrensPrice extends Price { public int { return Movie.CHILDRENS; class NewReleasePrice extends Price { public int { return Movie.NEW_RELEASE; public Movie(String name, int pricecode) { _name = name; setpricecode(pricecode); public int { return _price.; public void setpricecode(int arg) { switch (arg) { case REGULAR: _price = new RegularPrice(); break; case CHILDRENS: _price = new ChildrensPrice(); break; case NEW_RELEASE: _price = new NewReleasePrice(); break; default: throw new IllegalArgumentException( Incorrect price code );

Schritt 4-5: Fallunterscheidung durch Polymorphimus ersetzen class Movie {... public double charge(int daysrented) { return _price.charge(daysrented); d) 4 class Price {... public double charge(int daysrented) { double result = 0; switch () { case Movie.REGULAR: result += 2; if (daysrented() > 2) result += (daysrented()-2).5; break; case Movie.CHILDRENS: result +=.5; if (daysrented() > 3) result += ( daysrented()-3).5; break; case Movie.NEW_RELEASE: result +=daysrented()3; break; 5 abstract class Price... abstract public double charge(int days); class RegularPrice extends Price {... public double charge(int daysrented){ double result =2; if (daysrented > 2) result += (daysrented d -2).5; return result; class ChildrensPrice extends Price {... public double charge(int daysrented){ double result =.5; if (daysrented > 3) result += (daysrented -3).5; return result; class NewReleasePrice extends Price {... public double charge(int daysrented) { return daysrented 3;

Vorlesung Softwaretechnologie Wintersemester este 2009 R O O T S Rückblick auf das Beispiel: Zusammenfassung der Refactoring- Schritte

Schritte zur Besserung: Rückblick Customer Rental Movie invoice() daysrented:int getdaysrented():int getmovie():movie pricecode:int setpricecode() Customer invoice() Rental daysrented:int getdaysrented():int getmovie():movie charge() bonuspoints () Movie pricecode:int setpricecode() Customer invoice() totalcharge() totalbonuspoints() invoiceashtml() Rental daysrented:int getdaysrented():int getmovie():movie charge() bonuspoints () Movie pricecode:int setpricecode() 2000-2009 Dr. G. Kniesel Vorlesung Softwaretechnologie (SWT) Seite 0-58 R O O T S

Schritte zur Besserung: Rückblick (2) Customer Rental Movie invoice() totalcharge() totalbonuspoints() invoiceashtml() daysrented:int getdaysrented():int getmovie():movie charge() bonuspoints () pricecode:int setpricecode() charge(days:int) bonuspoints(days:int) Customer invoice() totalcharge() totalbonuspoints() invoiceashtml() Rental daysrented:int getdaysrented():int getmovie():movie charge() bonuspoints () Movie pricecode:int setpricecode() 2000-2009 Dr. G. Kniesel Vorlesung Softwaretechnologie (SWT) Seite 0-59 R O O T S

Schritte zur Besserung: Rückblick (3) Customer Rental Movie invoice() totalcharge() totalbonuspoints() invoiceashtml() daysrented:int getdaysrented():int getmovie():movie charge() bonuspoints () pricecode:int setpricecode() charge(days:int) bonuspoints(days:int) Price pricecode:int charge(days:int) bonuspoints(days:int) OtherPrice ChildrensPrice NewReleasePrice RegularPrice charge(days:int) bonuspoints(days:int) charge(days:int) charge(days:int) bonuspoints(days:int) charge(days:int) 2000-2009 Dr. G. Kniesel Vorlesung Softwaretechnologie (SWT) Seite 0-60 R O O T S

Endzustand: Klassen-Diagramm Customer Rental Movie invoice() totalcharge() totalbonuspoints() invoiceashtml() daysrented:int getdaysrented():int getmovie():movie charge() bonuspoints () pricecode:int setpricecode() charge(days:int) bonuspoints(days:int) Price pricecode:int charge(days:int) bonuspoints(days:int) OtherPrice ChildrensPrice NewReleasePrice RegularPrice charge(days:int) bonuspoints(days:int) charge(days:int) charge(days:int) bonuspoints(days:int) charge(days:int) 2000-2009 Dr. G. Kniesel Vorlesung Softwaretechnologie (SWT) Seite 0-6 R O O T S

Endzustand: Sequenz-Diagramm für invoice()-aufruf acustomer arental amovie currentprice : aprice invoice() totalcharge() [for all rentals] charge() totalbonuspoints() charge(days) charge(days) [for all rentals] bonuspoints() bonuspoints bonuspoints (days) (days) 2000-2009 Dr. G. Kniesel Vorlesung Softwaretechnologie (SWT) Seite 0-62 R O O T S

Nutzen: Einfache Erweiterbarkeit (2) class Movie... public void setpricecode(int arg) { switch (arg) {... case NEUE_KATEGORIE: _price = new NewCategoryPrice(); break;... abstract class Price { abstract int ; abstract double charge(days:int);... class NewCategoryPrice extends Price {... Neue Preiskategorie erfordert nur zusätzliche Klasse Änderung bestehenden Codes an genau einer Stelle 2000-2009 Dr. G. Kniesel Vorlesung Softwaretechnologie (SWT) Seite 0-64 R O O T S

Vorlesung Softwaretechnologie Wintersemester este 2009 R O O T S Was also ist Refactoring?

Was ist Refactoring? Refactoring (noun): a change made to the internal structure of software to make it easier to understand and cheaper to modify without changing its observable behavior. Refactor (verb): to restructure software by applying ppy a series of refactorings. Definition Systematische Umstrukturierung des Codes ohne das Verhalten nach außen zu ändern Nutzen bessere Lesbarkeit, Verständlichkeit besseres Design bessere Wartbarkeit und Wiederverwendbarkeit db it 2000-2009 Dr. G. Kniesel Vorlesung Softwaretechnologie (SWT) Seite 0-68 R O O T S

Was heißt "Systematische Umstrukturierung"? Klare Anweisungen was wann wie Festgelegter Ablauf kleine Schritte Tests nach jedem Schritt Disziplin! 2000-2009 Dr. G. Kniesel Vorlesung Softwaretechnologie (SWT) Seite 0-69 R O O T S

Ablauf: Kent Beck's "Hüte-Metapher" Was will ich umstrukturieren? Gibt es einen Test? Test schreiben! Refactoring durchführen Testen Fehler beheben! Refactoring Hat Programmer Function Adding Hat Was will ich hinzufügen?? Test schreiben Funktionserweiterung durchführen Testen Fehler beheben!

Vorlesung Softwaretechnologie Wintersemester este 2009 R O O T S Refactoring Schritt für Schritt Refactoring Extract Method als Beispiel was mit systematischem Vorgehen beim Refactoring Refactoring Extract Method als Beispiel was mit systematischem Vorgehen beim Refactoring gemeint ist

Refactoring-Katalog (siehe Buch von Martin Fowler) Komposition von Methoden Extract Method Inline Method Replace Temp with Query Inline Temp Split Temporary Variable Remove Assignments to Parameters Replace Method with Method Object... Verlagerung von Methoden... Strukturierung von Daten... Vereinfachung von Fallunterscheidungen... Vereinfachung von Methodenaufrufen... Vererbung...

Extract Method Indikation Code-Fragment das logisch zusammengehört Behandlung durch aussagekräftig benannte Methode ersetzen void printowing(double amount) { printbanner(); // print details System.out.println( name +_name); System.out.println( amount + amount); void printowing (double amount) { printbanner(); printdetails(amount); void printdetails (double amount) { System.out.println ( name +_name); name); System.out.println ( amount + amount);

Schritte Neue Methode erzeugen und sinnvoll benennen immer private Code kopieren Lokale Variablen der Ursprungsmethode im extrahierten Code suchen Variablen, die nur noch in der neuen Methode benutzt werden lokale Variablen der neuen Methode Variablen, die in der neuen Methode verwendet werden Parameter der neuen Methode Variablen, die in neuer Methode verändert und in der alten weiter benutzt t werden falls nur eine: als Ergebnis der neuen Methode zurückgeben mehr als eine: Teilmethode nicht extrahierbar! (evtl. vorbereitend andere Refactorings versuchen, die Variablen eliminieren oder Gruppen von Variablen zu einem Objekt zusammenfassen) Kompilieren In Ursprungsmethode extrahierten Code ersetzen durch Aufruf der neuen Methode Deklaration nicht mehr benötigter lokaler Variablen löschen Kompilieren Testen 2000-2009 Dr. G. Kniesel Vorlesung Softwaretechnologie (SWT) Seite 0-75 R O O T S

Beispiel: keine lokalen Variablen im extrahierten Block void printowing(double amount) { Enumeration e = :orders.elements(); double outstanding = 0.0; // print banner System.out.println(""); t tl System.out.println(" Customer owes "); System.out.println(""); // calculate l outstanding t while (e.hasmoreelements()) { Order each = (Order) e.nextelement(); outstanding += each.getamount(); // print details System.out.println( name + _name); System.out.println( amount + outstanding); Extraktion des Codes für Banner-Druck 2000-2009 Dr. G. Kniesel Vorlesung Softwaretechnologie (SWT) Seite 0-76 R O O T S

Beispiel: keine lokalen Variablen im extrahierten Block void printowing(double amount) { Enumeration e = :orders.elements(); double outstanding = 0.0; private void printbanner() { printbanner(); System.out.println(""); System.out.println(" Customer owes "); System.out.println(""); // calculate l outstanding t while (e.hasmoreelements()) { Order each = (Order) e.nextelement(); outstanding += each.getamount(); // print details System.out.println( name + _name); System.out.println( amount + outstanding); Extraktion des Codes für "print details" lokale Variable, die nicht verändert wird ( outstanding ) 2000-2009 Dr. G. Kniesel Vorlesung Softwaretechnologie (SWT) Seite 0-77 R O O T S

Beispiel: lokale Variable, die nicht verändert wird void printowing(double amount) { Enumeration e = :orders.elements(); double outstanding = 0.0; printbanner(); // calculate l outstanding t while (e.hasmoreelements()) { Order each = (Order) e.nextelement(); outstanding += each.getamount(); printdetails(outstanding); private void printdetails(double outstanding) { System.out.println( name + _name); System.out.println( amount + outstanding); Extraktion des Codes für die Berechnung lokale Variable, die verändert und anschließend benutzt wird ( outstanding ) lokale Variable, die verändert und anschließend nicht mehr benutzt wird ( e )

Beispiel: lokale Variable, die verändert wird void printowing(double amount) { Enumeration e = :orders.elements(); double outstanding = 0.0; printbanner(); outstanding t = getoutstanding(); t t private double getoutstanding() { Enumeration e = orders.elements(); double outstanding = 0.0; printdetails(outstanding); while (e.hasmoreelements()) { Order each = (Order) e.nextelement(); outstanding += each.getamount(); return outstanding ; Extraktion des Codes für die Berechnung falls lokale Variable, vorher in der Ursprungsmethode zugewiesen wird

Beispiel: lokale Variable, die verändert wird (auch vorher) void printowing(double amount) { double outstanding = amount.2; printbanner(); outstanding t = getoutstanding(outstanding); t t t t private double getoutstanding(double getoutstanding() { startvalue) { Enumeration e = orders.elements(); double outstanding result = 0.0; startvalue; printdetails(outstanding); while (e.hasmoreelements()) { Order each = (Order) e.nextelement(); result outstanding += each.getamount(); return outstanding result ; Extraktion Nun sind weitere des Codes Refactorings für die Berechnung möglich falls zweimaliges lokale Variable, inline temp vorher für in Zuweisungen der Ursprungsmethode an lokale Variable zugewiesen outstanding wird so kann outstanding aus printowing -Methode eliminiert werden

Beispiel: Elimination von outstanding void printowing(double amount) { double outstanding = amount.2; printbanner(); outstanding t = getoutstanding(outstanding); t t t t printdetails(outstanding); Nun sind weitere Refactorings möglich zweimaliges inline temp für Zuweisungen an lokale Variable outstanding so kann outstanding aus printowing -Methode eliminiert werden

Beispiel: Endzustand von printowing() und extrahierte Methoden void printowing(double amount) { printbanner(); private void printbanner() { System.out.println(""); System.out.println(" Customer owes "); System.out.println(""); private void printdetails(double outstanding) { System.out.println( name + _name); System.out.println( println( amount + outstanding); printdetails(getoutstanding(amount.2)); private double getoutstanding(double startvalue) { Enumeration e = orders.elements(); elements(); double result = startvalue; while (e.hasmoreelements()) { Order each = (Order) e.nextelement(); result += each.getamount(); return result;

Vorlesung Softwaretechnologie Wintersemester este 2009 R O O T S Bad Smells Indikationen für Bad Smells Indikationen für Refactoring

Lange Parameterliste Problem Verständlichkeit Fehleranfälligkeit dauernde Änderungen Idee Parameter-Werte aus bereits bekannten Objekten besorgen Parameter ersetzen durch Methodenaufruf an anderen Parameter oder Instanz-Variable Parametergruppe ersetzen durch Objekt aus dem die Werte stammen anschließend Mehodenaufrufe an diesen einen Parameter Parametergruppe durch Objekt einer neuen Klasse ersetzen für ansonsten nicht zusammengehörige Parameter Ausnahme wenn man bewusst keine Abhängigkeit gg zu einer bestimmten Klasse erzeugen will 2000-2009 Dr. G. Kniesel Vorlesung Softwaretechnologie (SWT) Seite 0-85 R O O T S

Lange Parameterliste: Beispiel Vorher Nachher obj.method(w, w.get2(), x.get3(), x.get4(), y, z); ) obj.method(w, x, newparam); ) void method(a, a2, a3, a4, a5, a6){... void method(a, a34, a56) { a2 = w.get2(); a3 = a34.get3(); a4 = a34.get4(); a5 = a56.gety(); a6 = a56.getz();... Abhängigkeiten an jeder Aufrufstelle Typ von w Typ von x Typ von y Typ von z Abhängigkeiten in Methode Typ von w Typ von x Typ von newparam 2000-2009 Dr. G. Kniesel Vorlesung Softwaretechnologie (SWT) Seite 0-86 R O O T S

Änderungsanfälligkeit ( Divergente Änderungen ) Symptom verschiedene Änderungsarten betreffen gleiche Klasse Beispiel neue Datenbank: Methode bis 3 in Klasse C ändern neue Kontoart: Methode 6 bis 8 in Klasse C ändern Behandlung Klasse aufteilen C_DB Methode bis 3 C_Konto Methode 6 bis 8 C Restliche Methoden Effekt Lokalisierung von Änderungen 2000-2009 Dr. G. Kniesel Vorlesung Softwaretechnologie (SWT) Seite 0-87 R O O T S

Verteilte Änderungen Symptom eine Änderung betriff viele Klassen Problem schlechte Modularisierung Fehleranfälligkeit Behandlung Methoden verlagern Felder verlagern... so dass Änderungen in nur einer Klasse erforderlich sind Evtl. geeignete Klasse erzeugen EtlKl Evtl. Klassen zusammenfassen Effekt Lokalisierung von Änderungen 2000-2009 Dr. G. Kniesel Vorlesung Softwaretechnologie (SWT) Seite 0-88 R O O T S

Neid: Begehre nicht deines Nächsten Hab und Gut! Symptom Methode die sich vorwiegend um eine bestimmte t anderen Klasse kümmert Typisch: viele get...() -Aufrufe an andere Klasse Behandlung allgemein Neidische Methode in andere Klasse verlagern evtl. neidischen Teil der Methode extrahieren und verlagern Behandlung nicht-eindeutiger Fälle Methode in Klasse verlagern die am stärksten beneidet wird oder verschiedene Teilmethoden in verschiedene Klassen verlagern Ausnahmen Strategy und Visitor Pattern allgemein: Bewusste Dekomposition um divergente Änderungen zu bekämpfen 2000-2009 Dr. G. Kniesel Vorlesung Softwaretechnologie (SWT) Seite 0-89 R O O T S

Daten-Klumpen Symptom Daten die immer gemeinsam vorkommen/ benutzt t werden Instanzvariablen oder Parameter Behandlung Extraktion der Daten in eigene Klasse Extract t Class Introduce Parameter Object Preserve Whole Object anschließend anhand Neid -Kriterium Methoden verlagern Effekt bessere Modularisierung kürzere Parameterlisten 2000-2009 Dr. G. Kniesel Vorlesung Softwaretechnologie (SWT) Seite 0-90 R O O T S

Fixierung auf primitive Datentypen Symptom viele Variablen von primitiven iti Datentypen t Beispiel: String adresse Behandlung Extraktion der Variablen in eigene Klasse Allgemein Replace Data Value with Object : Adresse adresse Typ-Codierung Replace Type Code with Class Replace Type Code with Subclasses Replace Type Code with State / Strategy mehrere e e zusammengehörige Variablen abe Effekt s. Daten-Klumpen bessere Erweiterbarkeit 2000-2009 Dr. G. Kniesel Vorlesung Softwaretechnologie (SWT) Seite 0-9 R O O T S

Fallunterscheidungen (Switch- Statements) Symptom Fallunterscheidungen selektiert t Methodenaufrufe f oft in Verbindung mit Typ-Code Problem Redundanz: oft gleiche Fallunterscheidungen an vielen Stellen schlechte Erweiterbarkeit Behandlung Fallunterscheidungen als Teilmethode extrahieren... in Klasse verlagern zu der der Typ-Code logisch gehört... Typ-Code durch Unterklassen ersetzen Replace Type Code with Subclasses... jeden Fall in entsprechende Methode einer Unterklassen verlagern Replace Conditional with Polymorphism Wenn dabei eine neue Klassenhierarchie für Typ-Code erzeugt wird Replace Type Code with State / Strategy 2000-2009 Dr. G. Kniesel Vorlesung Softwaretechnologie (SWT) Seite 0-92 R O O T S

Fallunterscheidung (Fortsetzung) Behandlung bei wenigen, festgelegten Alternativen... wenn also keine Erweiterbarkeit erforderlich ist Replace Parameter with explicit Methods Eigene Methode für jeden Fall Fallunterscheidung eliminieren Aufrufer ruft spezifische Methode auf, statt spezifischen Typ-Code zu setzen Behandlung von Tests auf null Introduce Null Object Effekte Erwarteten Objekttyp um eine Unterklasse erweitern... deren Methoden das tun, was im null null Fall getan werden soll Statt null solche Null-Objekte übergeben Fallunterscheidung eliminieren einfacherer Code keine Redundanzen bessere Erweiterbarkeit 2000-2009 Dr. G. Kniesel Vorlesung Softwaretechnologie (SWT) Seite 0-93 R O O T S

Faule Klasse Symptom Klassen, die fast nichts mehr tun Überbleibsel des Refactoring-Prozesses auf Verdacht angelegt und dann doch nie benötigt Problem jede faule Klasse bringt unnötige Kosten Wartungs- Verständnis- Laufzeit- das gleiche gilt für faule Hierarchien ( faule Unterklassen ) Behandlung Eliminierung der faulen Klasse faule Unterklasse in Oberklasse integrieren ( Collapse Hierarchy ) faule Klasse in Client integrieren ( Inline Class ) 2000-2009 Dr. G. Kniesel Vorlesung Softwaretechnologie (SWT) Seite 0-94 R O O T S

Spekulative Allgemeinheit Symptom Jemand sagt: Ich glaub man wird auch mal... brauchen. Problem komplexeres Design schwerer zu verstehen schwerer zu benutzen schwerer zu warten... und all das, nur auf Verdacht, ohne das es wirklich gebraucht wird! Behandlung faule faule abstrakte Klassen: eliminieren ( Collapse Hierarchy ) überflüssiges Forwarding: Aggregat in Client integrieren ( Inline Class ) überflüssige Parameter: eliminieren ( Remove Parameter ) übermäßig abstrakte Methodennamen: umbenennen 2000-2009 Dr. G. Kniesel Vorlesung Softwaretechnologie (SWT) Seite 0-95 R O O T S

Temporäre Felder Symptom Instanz-Variablen, die manchmal nicht initialisiert / benutzt werden Beispiel eine Methode implementiert komplexen Algorithmus der viele Parameter hat Parameter werden nicht übergeben, sondern als Instanzvariablen angelegt Problem Verständnis ( Was soll das denn? ) Behandlung Variable und darauf zugreifende Methoden ein eigene Klasse extrahieren Effekt bessere Verständlichkeit bessere Modularisierung 2000-2009 Dr. G. Kniesel Vorlesung Softwaretechnologie (SWT) Seite 0-96 R O O T S

Verweigertes Vermächtnis Symptom Unterklassen nutzen geerbte Variablen nicht Unterklassen implementieren geerbte Methoden so dass sie nichts tun oder Exceptions werfen Problem Vererbung falsch angewendet Subtypbeziehung nicht angebracht Behandlung Vererbungs-Hierarchie verändern verweigerte Anteile aus Oberklasse in neue Unterklasse auslagern verweigernde Methoden aus anderen Unterklassen eliminieren oder Vererbung durch Aggregation und Forwarding ersetzen 2000-2009 Dr. G. Kniesel Vorlesung Softwaretechnologie (SWT) Seite 0-98 R O O T S

Kommentare im Methoden-Rumpf Symptom Kommentar erklärt was als nächstes geschieht Problem Code ist offensichtlich nicht verständlich genug Behandlung Teilmethode extrahieren (mit aussagekräftigem Namen) Teilmethoden umbenennen (aussagekräftigere Namen) Assertions benutzen um Randbedingungen explizit zu machen Effekt selbstdokumentierender Code selbstcheckender Code (Assertions) 2000-2009 Dr. G. Kniesel Vorlesung Softwaretechnologie (SWT) Seite 0-99 R O O T S

Vorlesung Softwaretechnologie Wintersemester este 2009 R O O T S Refactoring Zusammenfassung Warum soll ich es anwenden? Wann soll ich es anwenden? Refactoring und Design Refactoring und Effizienz Wie sag ich's dem Chef? Wo sind die Grenzen?

Warum soll man Refactoring anwenden? Programme sind schwer zu warten wenn sie... unverständlich sind... Redundanzen enthalten... komplexe Fallunterscheidungen enthalten... Änderungen bestehenden Codes erfordern, um Erweiterungen zu implementieren Probleme Oft geänderte Software verliert ihre Struktur. Je mehr Code um so unverständlicher Redundanter Code / Inkonsistenzen 2000-2009 Dr. G. Kniesel Vorlesung Softwaretechnologie (SWT) Seite 0-02 R O O T S

Warum soll man Refactoring anwenden? Refactoring macht Software leichter wartbar Extraktion gemeinsamer Teile: jede Änderung an genau einer Stelle durchführen "Rule of three": Wenn man das zweite Mal das gleiche tut ist Code- Duplizierung noch OK. Beim dritten Mal sollte spätestens Umstrukturiert werden. Refactoring macht Software leichter verständlich Einarbeitung ist leichter, wenn man sofort restrukturiert hilft einem selbst und denen die später kommen Refactoring hilft Bugs zu finden besseres Verständnis für den Code erleichtert Fehlersuche Refactoring macht das Programmieren schneller in verständlichen ist und fehlerarmen Code kann Neues schneller eingebaut werden