Advanced Software Engineering WS0910 Kapitel3. Dr. Dominik Haneberg

Ähnliche Dokumente
Advanced Software Engineering WS0910 Kapitel3. Dr. Dominik Haneberg

Refactoring. PG Reclipse Seminar: Refactoring Jan-Christopher Bals (1/30)

0/100. Refactoring. Andreas Zeller. Lehrstuhl Softwaretechnik Universität des Saarlandes, Saarbrücken

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!

Modularisierung. Klausur. Evaluation. Andreas Zeller. Objektorientierung C++ Sonstiges 33% 33% 33%

86 Software Engineering, SoSe 07, WSI, D. Huson, (Original Author: A. Zeller), 2. Juli 2007

Kapitel 11 Kapitel 11 Refactoring

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

Vorlesung Softwaretechnologie. Wintersemester este 2008 R O O T S. Refactoring. Stand: (Selbsttestfolie eingefügt)

Kapitel 11 Refactoring

Kapitel 10 Refactoring

Kapitel 11 Refactoring

2 + 1, 50 pro Tag ab dem 3. Tag. 1, 50 plus 1, 50 pro Tag ab dem 4. Tag

Refactoring. Programmiermethodik. Eva Zangerle Universität Innsbruck

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

Software-Refactoring. 29. Mai 2013

Kapitel 3 Software Quality II

Vorlesung Software-Reengineering

Vorlesung Software-Reengineering

Software-Refactoring. 27. Mai 2015

Refactoring Transformationen. Martin Freund Januar 2003 Seminar Refactoring in extreme Programming AG Kastens Universität Paderborn

Java Einführung Vererbung und Polymorphie. Kapitel 13

Refactoring. Uschi Beck

Java Einführung Abstrakte Klassen und Interfaces

Javadoc. Programmiermethodik. Eva Zangerle Universität Innsbruck

Javakurs FSS Lehrstuhl Stuckenschmidt. Tag 3 - Objektorientierung

Interface. So werden Interfaces gemacht

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

12 Abstrakte Klassen, finale Klassen und Interfaces

Einstieg in die Informatik mit Java

Info B VL 11: Innere Klassen/Collections

1 Abstrakte Klassen, finale Klassen und Interfaces

Programmiermethodik 3. Klausur Lösung

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

Objektorientierte Programmierung. Kapitel 22: Aufzählungstypen (Enumeration Types)

14 Abstrakte Klassen, finale Klassen, Interfaces

14 Abstrakte Klassen, finale Klassen, Interfaces. Auswertung von Ausdrücken. Beispiel. Abstrakte Methoden und Klassen

5. Tutorium zu Programmieren

Algorithmen und Datenstrukturen

Kapitel 5: Interfaces

Übersetzen des Quelltexts in ausführbaren Maschinen-Code Translation of source code into executable machine code

Programmieren in Java

Klassen und ihre Beziehungen III: Mehrfache Vererbung, Rollen, Schnittstellen und Pakete

Kapitel 7 Refactoring I

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

Einstieg in die Informatik mit Java

Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 16/17. Kapitel 13. Listen. Listen 1

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

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

12. Java Klassen. Klassen - Technisch. Beispiel: Erdbebendaten. Klassen - Konzeptuell

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

Seminar: CASE-Tools WS 06/ Refactoring. Thomas Löffler

7.0 Arbeiten mit Objekten und Klassen

Vererbung. Gerd Bohlender. Institut für Angewandte und Numerische Mathematik. Vorlesung: Einstieg in die Informatik mit Java 23.5.

Softwaretechnik WS 16/17. Übungsblatt 01

Theorie zu Übung 8 Implementierung in Java

Programmieren 2 Java Überblick

Refactoring I. Nach Martin Fowler - Refactoring

Probeklausur: Programmierung WS04/05

Einstieg in die Informatik mit Java

Java Tools JDK. IDEs. Downloads. Eclipse. IntelliJ. NetBeans. Java SE 8 Java SE 8 Documentation

Vererbung, Polymorphie

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

Jan Schumann, G+J Manuel Pichler, Trainer & Consultant - Qafoo. Statische Codeanalyse wirklich effektiv nutzen

Schlussendlich geben wir die Listen aus. Es kommt zu folgender Ausgabe:

4. Kontrollstrukturen Programmieren / Algorithmen und Datenstrukturen 1 Prof. Dr. Bernhard Humm FB Informatik, Hochschule Darmstadt

Johannes Link.

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

Assoziation und Aggregation

Grundzüge der Programmierung. Wiederverwendung VERERBUNG

Polymorphie/Späte Bindung Abstrakte Klassen Interfaces. Polymorphie/Späte Bindung Abstrakte Klassen Interfaces

Programmierung für Mathematik (HS13)

Eine Klasse beschreibt Objekte mit gleichen Attributen und Methoden.

II. Grundlagen der Programmierung. Beispiel: Merge Sort. Beispiel: Merge Sort (Forts. ) Beispiel: Merge Sort (Forts. )

Nachklausur Programmieren / Algorithmen und Datenstrukturen 1

Informatik II. Giuseppe Accaputo, Felix Friedrich, Patrick Gruntz, Tobias Klenze, Max Rossmannek, David Sidler, Thilo Weghorn FS 2017

TU München, Fakultät für Informatik Lehrstuhl III: Datenbanksysteme Prof. Alfons Kemper, Ph.D.

Neben der Verwendung von Klassen ist Vererbung ein wichtiges Merkmal objektorientierter

Programmieren I + II Regeln der Code-Formatierung

! 1. Unterklassen und Vererbung! 2. Abstrakte Klassen und Interfaces! 3. Modularität und Pakete. II.4.2 Abstrakte Klassen und Interfaces - 1 -

Objektorientierung (OO)

Übung Informatik I - Programmierung - Blatt 8

Kapitel Was ist ein Header? Was ist ein Body? Header: public Account(String newowner, int newpin)

Algorithmen und Datenstrukturen Musterlösung 5

Programmieren in Java -Eingangstest-

Ersetzbarkeit und Verhalten

3 Objektorientierte Konzepte in Java

Client-Server-Beziehungen

Einführung in die Programmierung I. 2.0 Einfache Java Programme. Thomas R. Gross. Department Informatik ETH Zürich

Introduction to Python. Introduction. First Steps in Python. pseudo random numbers. May 2016

Java-Schulung Grundlagen

Programmieren in Java

II.4.2 Abstrakte Klassen und Interfaces - 1 -

Javakurs für Anfänger

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

Th. Letschert OOP 2 2. Geheimnisprinzip und Sichtbarkeitsbeziehungen

Ein Stern in dunkler Nacht Die schoensten Weihnachtsgeschichten. Click here if your download doesn"t start automatically

Harry gefangen in der Zeit Begleitmaterialien

Transkript:

Advanced Software Engineering WS0910 Kapitel3 Dr. Dominik Haneberg

REFACTORING 01.02.2010 Advanced Software Engineering 2

Inhalte dieses Kapitels Was ist Refactoring? Wozu und wann refactorn? Wie geht man vor? Beispiel für ein Refactoring (im Kleinen und im Großen) Code Smells und übliche Refactorings 01.02.2010 Advanced Software Engineering 3

GRUNDBEGRIFFE IM REFACTORING 01.02.2010 Advanced Software Engineering 4

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. Refactoring (verb): To restructure software by applying a series of refactorings. Definition: Systematische Umstrukturierung von Code ohne dessen Verhalten zu ändern Nutzen: Bessere Lesbarkeit und Verständlichkeit Besseres Design Besser Wartbarkeit und Wiederverwendbarkeit M. Fowler: Refactoring Improving the Design of Existing Code, Addison- Wesley, 1999 01.02.2010 Advanced Software Engineering 5

Warum Refactorings 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 01.02.2010 Advanced Software Engineering 6

Vorgehen Wann refactorn? Ständig: Es gibt keinen festen Refactoring Zeitslot Wenn man Code liest und zu verstehen versucht Rule of Three Beim Hinzufügen neuer Funktionalität Beim Entfernen von Fehlern Bei Code Reviews Vorgehen Code Smell erkannt Ausreichend Unittests vorhanden und erfolgreich Refactoring anwenden Mit Unittests Erhalt der Funktionalität prüfen 01.02.2010 Advanced Software Engineering 7

Code Smells und Refactorings Code Smell: code smell is any symptom in the source code of a program that possibly indicates a deeper problem. Der Begriff geht auf Kent Beck zurück Bezeichnet Strukturen/Muster im Code, die auf schlechtes OO-Design, schlechte Wartbarkeit, Verständlichkeit usw. hindeuten Beispiele: Duplicate Code Large Class Inappropriate intimacy Large Method 01.02.2010 Advanced Software Engineering 8

Code Smells und Refactorings Refactoring: Präzise Vorgehensbeschreibung für eine Änderung am Code, mit dem Ziel einer Strukturverbesserung Bestandteile eines Refactorings: Problembeschreibung (Code Smell) Kurze Beschreibung der Codeänderung Schritt für Schritt Änderungsvorschrift Motivation für die Codeänderung (folgt oftmals aus den Grundprinzipien für gutes OO-Design) Ggf. Beispiele 01.02.2010 Advanced Software Engineering 9

Beispiel für ein Refactoring Introduce Explaining Variable Problem: You have a complicated expression Kurzfassung der Änderung: Put the result of the expression, or parts of the expression, in a temporary variable with a name that explains the purpose. Motivation: Expressions can become very complex and hard to read. In such situations temporary variables can be helpful to break down the expression into something more manageable. Introduce Explaining Variable is particularly valuable with conditional logic 01.02.2010 Advanced Software Engineering 10

Beispiel für ein Refactoring Introduce Explaining Variable Vorgehensweise: Declare final temporary variable, and set it to the result of a part of the complex expression. Replace the result part of the expression with the temp. If the result part of the expression is repeated, you can replace the repeats one at a time Compile and test. Repeat for other parts of the expression. 01.02.2010 Advanced Software Engineering 11

Beispiel für ein Refactoring Introduce Explaining Variable Beispiel: if ( (platform.touppercase().indexof("mac") > -1) && (browser.touppercase().indexof("ie") > -1) && wasinitialized() && resize > 0) { // do something 01.02.2010 Advanced Software Engineering 12

Beispiel für ein Refactoring Introduce Explaining Variable Beispiel: if ( (platform.touppercase().indexof("mac") > -1) && (browser.touppercase().indexof("ie") > -1) && wasinitialized() && resize > 0) { // do something final boolean ismaxos = platform.touppercase().indexof("mac") > -1; final boolean isiebrowser = browser.touppercase().indexof("ie") > -1; final boolean wasresized = resize > 0; if (ismacos && isiebrowser && wasinitialized() && wasresized) { // do something 01.02.2010 Advanced Software Engineering 13

EIN ANWENDUNGSBEISPIEL 01.02.2010 Advanced Software Engineering 14

Videos können im Laufe der Zeit zu verschiedenen Preiskategorien gehören (Normal, Kinder, 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 01.02.2010 Advanced Software Engineering 15

name: String Customer statement:string getname(): String addrental(rental) 1 daysrented: int Rental getdaysrented(): int getmovie(): Movie * rentals * 1 movie title: String pricecode: int gettitle(): String getpricecode(): int setpricecode(int) Movie 01.02.2010 Advanced Software Engineering 16

Movie: Eine einfache Datenklasse public class Movie { public static final int CHILDRENS = 2; public static final int REGULAR = 0; public static final int NEW_RELEASE = 1; private String title; private int pricecode; public Movie(String title, int pricecode) { this.title = title; this.pricecode = pricecode; public int getpricecode() { return pricecode; public void setpricecode(int pricecode) { this.pricecode = pricecode; public String gettitle() { return title; 01.02.2010 Advanced Software Engineering 17

Rental: Repräsentiert eine Ausleihe public class Rental { private Movie movie; private int daysrented; public Rental(Movie movie, int daysrented) { this.movie = movie; this.daysrented = daysrented; public int getdaysrented() { return daysrented; public Movie getmovie() { return movie; 01.02.2010 Advanced Software Engineering 18

Customer: Repräsentiert einen Kunden public class Customer { private String name; private Vector rentals = new Vector(); public Customer(String name) { this.name = name; public void addrental(rental newrental) { rentals.addelement(newrental); public String getname() { return name; 01.02.2010 Advanced Software Engineering 19

Customer: Die Methode statement() 01.02.2010 Advanced Software Engineering 20

Customer: Die Methode statement() public String statement() { double totalamount = 0; int frequentrenterpoints = 0; Enumeration rented = rentals.elements(); String result = Rental Record for + getname() + \n ; while (rented.hasmoreelements()) { double thisamount = 0; Rental each = (Rental) rented.nextelement(); //determine amounts for each line switch (each.getmovie().getpricecode()) { case Movie.REGULAR: thisamount += 2; if (each.getdaysrented() > 2) thisamount += (each.getdaysrented() - 2) * 1.5; break; case Movie.NEW_RELEASE: thisamount += each.getdaysrented() * 3; break; case Movie.CHILDRENS: thisamount += 1.5; if (each.getdaysrented() > 3) thisamount += (each.getdaysrented() 3) * 1.5; break; 01.02.2010 Advanced Software Engineering 21

Customer: Die Methode statement() // add frequent renter points frequentrenterpoints++; // add bonus for a two day new release rental if ((each.getmovie().getpricecode() == Movie.NEW_RELEASE) && each.getdaysrented() > 1) frequentrenterpoints++; // show figures for this rental result += \t + each.getmovie().gettitle() + \t + String.valueOf(thisAmount) + \n ; totalamount += thisamount; // add footer result += Amount owned is + String.valueOf(totalAmount) + \n ; result += You earned + String.valueOf(frequentRenterPoints) + frequent renter points ; return result; Something is rotten in the state of Denmark. 01.02.2010 Advanced Software Engineering 22

Eine neue Kundenanforderung ist umzusetzen Zusätzlich zu statement() ist nun auch eine HTML- Ausgabe gewünscht Und nun: Den Code duplizieren?? 01.02.2010 Advanced Software Engineering 23

Aufteilung und Umverteilung der Methode statement() Refactoring: Extract Method //determine amounts for each line switch (each.getmovie().getpricecode()) { case Movie.REGULAR: thisamount += 2; if (each.getdaysrented() > 2) thisamount += (each.getdaysrented() - 2) * 1.5; break; case Movie.NEW_RELEASE: thisamount += each.getdaysrented() * 3; break; case Movie.CHILDRENS: thisamount += 1.5; if (each.getdaysrented() > 3) thisamount += (each.getdaysrented() 3) * 1.5; break; 01.02.2010 Advanced Software Engineering 24

Aufteilung und Umverteilung der Methode statement() Refactoring: Extract Method public int amountfor(rental each) { int thisamount = 0; switch (each.getmovie().getpricecode()) { case Movie.REGULAR: thisamount += 2; if (each.getdaysrented() > 2) thisamount += (each.getdaysrented() - 2) * 1.5; break; case Movie.NEW_RELEASE: thisamount += each.getdaysrented() * 3; break; case Movie.CHILDRENS: thisamount += 1.5; if (each.getdaysrented() > 3) thisamount += (each.getdaysrented() 3) * 1.5; break; return thisamount; 01.02.2010 Advanced Software Engineering 25

Aufteilung und Umverteilung der Methode statement() Refactoring: Extract Method public String statement() { double totalamount = 0; int frequentrenterpoints = 0; Enumeration rented = rentals.elements(); String result = Rental Record for + getname() + \n ; while (rented.hasmoreelements()) { double thisamount = 0; Rental each = (Rental) rented.nextelement(); thisamount = amountfor(each); 01.02.2010 Advanced Software Engineering 26

Aufteilung Falscher und Umverteilung Typ der Methode statement() Refactoring: Extract Method public int amountfor(rental each) { int thisamount = 0; switch (each.getmovie().getpricecode()) { case Movie.REGULAR: thisamount += 2; if (each.getdaysrented() > 2) thisamount += (each.getdaysrented() - 2) * 1.5; break; case Movie.NEW_RELEASE: thisamount += each.getdaysrented() * 3; break; case Movie.CHILDRENS: thisamount += 1.5; if (each.getdaysrented() > 3) thisamount += (each.getdaysrented() 3) * 1.5; break; return thisamount; 01.02.2010 Advanced Software Engineering 27

Gute Namen in amountfor() In der neuen Methode sind noch einige Variablennamen schlecht public double amountfor(rental each) { double thisamount = 0; switch (each.getmovie().getpricecode()) { case Movie.REGULAR: thisamount += 2; if (each.getdaysrented() > 2) thisamount += (each.getdaysrented() - 2) * 1.5; break; case Movie.NEW_RELEASE: thisamount += each.getdaysrented() * 3; break; case Movie.CHILDRENS: thisamount += 1.5; if (each.getdaysrented() > 3) thisamount += (each.getdaysrented() 3) * 1.5; break; return thisamount; 01.02.2010 Advanced Software Engineering 28

Gute Namen in amountfor() In der neuen Methode sind noch einige Variablennamen schlecht public double amountfor(rental arental) { double result = 0; switch (arental.getmovie().getpricecode()) { case Movie.REGULAR: result += 2; if (arental.getdaysrented() > 2) result += (arental.getdaysrented() - 2) * 1.5; break; case Movie.NEW_RELEASE: result += arental.getdaysrented() * 3; break; case Movie.CHILDRENS: result += 1.5; if (arental.getdaysrented() > 3) result += (arental.getdaysrented() 3) * 1.5; break; return result; Any fool can write code that a computer can understand. Good programmers write code that humans can understand. 01.02.2010 Advanced Software Engineering 29

amountfor() in die Klasse Rental verschieben Refactoring: Move Method public class Rental {... public double getcharge() { double result = 0; switch (getmovie().getpricecode()) { case Movie.REGULAR: result += 2; if (getdaysrented() > 2) result += (getdaysrented() - 2) * 1.5; break; case Movie.NEW_RELEASE: result += getdaysrented() * 3; break; case Movie.CHILDRENS: result += 1.5; if (getdaysrented() > 3) result += (getdaysrented() 3) * 1.5; break; return result; public class Customer { private double amountfor(rental arental) { return arental.getcharge(); 01.02.2010 Advanced Software Engineering 30

amountfor() in die Klasse Rental verschieben Refactoring: Move Method public String statement() { double totalamount = 0; int frequentrenterpoints = 0; Enumeration rented = rentals.elements(); String result = Rental Record for + getname() + \n ; while (rented.hasmoreelements()) { double thisamount = 0; Rental each = (Rental) rented.nextelement(); thisamount = each.getcharge(); 01.02.2010 Advanced Software Engineering 31

name: String Customer statement:string getname(): String addrental(rental) 1 daysrented: int Rental getdaysrented(): int getmovie(): Movie getcharge(): double * rentals * 1 movie title: String pricecode: int gettitle(): String getpricecode(): int setpricecode(int) Movie 01.02.2010 Advanced Software Engineering 32

Redundanz in der Methode statement() beseitigen Refactoring: Replace Temp with Query public String statement() { double totalamount = 0; int frequentrenterpoints = 0; Enumeration rented = rentals.elements(); String result = Rental Record for + getname() + \n ; while (rented.hasmoreelements()) { double thisamount = 0; Rental each = (Rental) rented.nextelement(); thisamount = each.getcharge(); // show figures for this rental result += \t + each.getmovie().gettitle() + \t + String.valueOf(thisAmount) + \n ; totalamount += thisamount; 01.02.2010 Advanced Software Engineering 33

Redundanz in der Methode statement() beseitigen Refactoring: Replace Temp with Query public String statement() { double totalamount = 0; int frequentrenterpoints = 0; Enumeration rented = rentals.elements(); String result = Rental Record for + getname() + \n ; while (rented.hasmoreelements()) { double thisamount = 0; Rental each = (Rental) rented.nextelement(); // show figures for this rental result += \t + each.getmovie().gettitle() + \t + String.valueOf(each.getCharge()) + \n ; totalamount += each.getcharge(); 01.02.2010 Advanced Software Engineering 34

Die frequent renter points in eigener Methode berechnen Refactoring: Extract Method while (rented.hasmoreelements()) { double thisamount = 0; Rental each = (Rental) rented.nextelement(); // add frequent renter points frequentrenterpoints++; // add bonus for a two day new release rental if ((each.getmovie().getpricecode() == Movie.NEW_RELEASE) && each.getdaysrented() > 1) frequentrenterpoints++; // show figures for this rental result += \t + each.getmovie().gettitle() + \t + String.valueOf(each.getCharge()) + \n ; totalamount += each.getcharge(); // add footer result += Amount owned is + String.valueOf(totalAmount) + \n ; result += You earned + String.valueOf(frequentRenterPoints) + frequent renter points ; return result; 01.02.2010 Advanced Software Engineering 35

Die frequent renter points in eigener Methode berechnen Refactoring: Extract Method und Move Method while (rented.hasmoreelements()) { double thisamount = 0; Rental each = (Rental) rented.nextelement(); frequentrenterpoints += each.getfrequentrenterpoints(); // show figures for this rental result += \t + each.getmovie().gettitle() + \t + String.valueOf(each.getCharge()) + \n ; totalamount += each.getcharge(); // add footer result += Amount owned is + String.valueOf(totalAmount) + \n ; result += You earned + String.valueOf(frequentRenterPoints) + frequent renter points ; return result; public class Rental { public int getfrequentrenterpoints() { if ((getmovie().getpricecode() == Movie.NEW_RELEASE) && getdaysrented() > 1) return 2; else return1; 01.02.2010 Advanced Software Engineering 36

name: String Customer statement:string getname(): String addrental(rental) 1 daysrented: int Rental getdaysrented(): int getmovie(): Movie getcharge(): double getfrequentrenterpoints(): int * rentals * 1 movie title: String pricecode: int gettitle(): String getpricecode(): int setpricecode(int) Movie 01.02.2010 Advanced Software Engineering 37

Die Methode statement() nach dem Refactoring 01.02.2010 Advanced Software Engineering 38

Weitere Hilfsvariablen eliminieren Refactoring: Replace Temp with Query while (rented.hasmoreelements()) { double thisamount = 0; Rental each = (Rental) rented.nextelement(); frequentrenterpoints += each.getfrequentrenterpoints(); // show figures for this rental result += \t + each.getmovie().gettitle() + \t + String.valueOf(each.getCharge()) + \n ; totalamount += each.getcharge(); // add footer result += Amount owned is + String.valueOf(totalAmount) + \n ; result += You earned + String.valueOf(frequentRenterPoints) + frequent renter points ; return result; 01.02.2010 Advanced Software Engineering 39

totalamount durch gettotalcharge() ersetzt Refactoring: Replace Temp with Query while (rented.hasmoreelements()) { double thisamount = 0; Rental each = (Rental) rented.nextelement(); frequentrenterpoints += each.getfrequentrenterpoints(); // show figures for this rental result += \t + each.getmovie().gettitle() + \t + String.valueOf(each.getCharge()) + \n ; // add footer result += Amount owned is + String.valueOf(getTotalCharge()) + \n ; result += You earned + String.valueOf(frequentRenterPoints) + frequent renter points ; return result; private double gettotalcharge() { double result = 0; Enumeration rented = rentals.elements(); while (rented.hasmoreelements()) { Rental each = (Rental) rented.nextelement(); result += each.getcharge(); return result; 01.02.2010 Advanced Software Engineering 40

name: String Customer statement:string getname(): String addrental(rental) gettotalcharge(): double gettotalfrequentrenterpoints(): int 1 daysrented: int Rental getdaysrented(): int getmovie(): Movie getcharge(): double getfrequentrenterpoints(): int * rentals * 1 movie title: String pricecode: int gettitle(): String getpricecode(): int setpricecode(int) Movie 01.02.2010 Advanced Software Engineering 41

Die Methode statement() nach dem Refactoring II 01.02.2010 Advanced Software Engineering 42

Eine neue Kundenanforderung ist umzusetzen Der Kunde denkt an eine Erweiterung seines Geschäfts. Es gibt neue Klassifikationen von Filmen und bestehende werden vielleicht geändert Und nun: Änderung in mehreren Methoden von Rental erforderlich (Fallunterscheidung über pricecode von Movie). Nichtlokale Änderungen sind nicht gut. 01.02.2010 Advanced Software Engineering 43

Schritt 1: getcharge und getfrequentrenterpoints in Klasse Movie public class Movie { public double getcharge(int daysrented) { double result = 0; switch (getpricecode()) { case Movie.REGULAR: result += 2; if (daysrented() > 2) result += (daysrented() - 2) * 1.5; break; case Movie.NEW_RELEASE: result += daysrented() * 3; break; case Movie.CHILDRENS: result += 1.5; if (daysrented() > 3) result += (daysrented() 3) * 1.5; break; return result; public class Rental { public double getcharge() { return movie.getcharge(daysrented); 01.02.2010 Advanced Software Engineering 44

name: String Customer statement:string getname(): String addrental(rental) gettotalcharge(): double gettotalfrequentrenterpoints(): int 1 daysrented: int Rental getdaysrented(): int getmovie(): Movie getcharge(): double getfrequentrenterpoints(): int * rentals * movie 1 title: String pricecode: int Movie gettitle(): String getpricecode(): int setpricecode(int) getcharge(): double getfrequentrenterpoints(): int 01.02.2010 Advanced Software Engineering 45

title: String pricecode: int Movie gettitle(): String getpricecode(): int setpricecode(int) getcharge(): double getfrequentrenterpoints(): int 1 Price getcharge(int) : double RegularPrice ChildrensPrice NewReleasePrice getcharge(int) : double getcharge(int) : double getcharge(int) : double 01.02.2010 Advanced Software Engineering 46

Zugriff auf Statusinformation über getter/setter Refactoring: Self Encapsulate Field public class Movie { public Movie(String title, int pricecode) { this.title = title; setpricecode(pricecode); public abstract class Price { public abstract int getpricecode(); public abstract class ChildrensPrice extends Price { public abstract int getpricecode() { return Movie.CHILDRENS; public abstract class RegularePrice extends Price { public abstract int getpricecode() { return Movie.REGULAR; public abstract class NewReleasePrice extends Price { public abstract int getpricecode() { return Movie.NEW_RELEASE; 01.02.2010 Advanced Software Engineering 47

pricecode wird durch ein price-feld ersetzt public class Movie { private Price price; public int getpricecode() { return price.getpricecode(); public void setpricecode(int pricecode) { switch (pricecode) { 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"); 01.02.2010 Advanced Software Engineering 48

getcharge() in Klasse Price public class Movie { public double getcharge(int daysrented) { return price.getcharge(daysrented) ; public class Price { public double getcharge(int daysrented) { double result = 0; switch (getpricecode()) { case Movie.REGULAR: result += 2; if (daysrented() > 2) result += (daysrented() - 2) * 1.5; break; case Movie.NEW_RELEASE: result += daysrented() * 3; break; case Movie.CHILDRENS: result += 1.5; if (daysrented() > 3) result += (daysrented() 3) * 1.5; break; return result; 01.02.2010 Advanced Software Engineering 49

Der letzte Schritt public class RegularPrice { public double getcharge(int daysrented) { double result = 2; if (daysrented > 2) result += (daysrented 2) * 1.5; return result; public class ChildrensPrice { public double getcharge(int daysrented) { double result = 1.5; if (daysrented > 3) result += (daysrented 3) * 1.5; return result; public class NewReleasePrice { public double getcharge(int daysrented) { return daysrented * 3; public class Price { public abstract double getcharge(int daysrented) ; 01.02.2010 Advanced Software Engineering 50

Die Aufrufsequenz nach den Refactorings 01.02.2010 Advanced Software Engineering 51

EINIGE REFACTORINGS 01.02.2010 Advanced Software Engineering 52

(Self) Encapsulate Field Zugriff auf Feld erfolgt direkt, aber die Koppelung an das Feld wird ungünstig Bei indirekten Zugriff übergang auf abgeleitetes Attribut möglich (z.b. in Unterklasse) Direkter Zugriff auf Feld von außen verlangt nach Wissen über Implementierungsdetail. Solche Informationen sollten verborgen werden. Zugriff über get-methode erlaubt lazy-initialization 01.02.2010 Advanced Software Engineering 53

(Self) Encapsulate Field Vorgehen get- und set-methoden anlegen Alle Referenzen auf das Feld suchen und durch Aufruf von get- bzw. set-methode ersetzen Feld als private deklarieren Nochmals prüfen, ob alle Verweise auf das Feld geändert wurden Kompilieren und testen 01.02.2010 Advanced Software Engineering 54

(Self) Encapsulate Field Beispiel private int low, high; boolean includes(int arg) { return arg >= low && arg <= high; private int low, high; boolean includes(int arg) { return arg >= getlow() && arg <= gethigh(); int getlow() { return low; int gethigh() { return high; 01.02.2010 Advanced Software Engineering 55

Move Method Eine Methode nutzt jetzt oder in Zukunft mehr Features einer anderen Klasse als derjenigen, in der sie definiert ist, oder die Methode wird häufiger von einer fremden Klasse benutzt als von der eigenen. Geschickte Positionierung von Methoden macht Klassen einfacher Coupling kann reduziert werden, Cohesion erhöht Verschieben von Feldern führt oft dazu, dass auch Methoden verschoben werden sollten 01.02.2010 Advanced Software Engineering 56

Move Method Vorgehen Alle Features, die die Quellmethode nutzt und die in der Quellklasse definiert sind, untersuchen, ob sie auch verschoben werden sollten Sub- und Superklassen auf weitere Definitionen der Methoden untersuchen Methode in der Zielklasse deklarieren Code in die Zielklasse kopieren. Ggf. an neue Umgebung anpassen, z.b. weitere Parameter Zielklasse kompilieren Festlegen, wie das korrekte Zielobjekt in der Quellklassen referenziert werden kann 01.02.2010 Advanced Software Engineering 57

Move Method Vorgehen Die Quellmethode in der Quellklasse in eine Methode abändern, die einen Aufruf an die neue Methode weiterleitet Kompilieren und testen Entscheiden ob die Quellmethode als Weiterleitungsmethode bleiben oder gelöscht werden soll Wenn die Quellmethode entfernt wird, alle Verweise auf sie mit Verweisen auf die neue Methode ersetzen Kompilieren und testen 01.02.2010 Advanced Software Engineering 58

Move Method Beispiel class Account double overdraftcharge() { if (type.ispremium()) { double result = 10; if (daysoverdrawn > 7) result += (daysoverdrawn 7) * 0,85; return result; else return daysoverdrawn * 1,75; double bankcharge() { double result = 4,5; if (daysoverdrawn > 0) result += overdraftcharge(); return result; private AccountType type; private int daysoverdrawn; 01.02.2010 Advanced Software Engineering 59

Move Method Beispiel class Account double bankcharge() { double result = 4,5; if (daysoverdrawn > 0) result += type.overdraftcharge(daysoverdrawn); return result; class AccountType double overdraftcharge(int daysoverdrawn) { if (ispremium()) { double result = 10; if (daysoverdrawn > 7) result += (daysoverdrawn 7) * 0,85; return result; else return daysoverdrawn * 1,75; 01.02.2010 Advanced Software Engineering 60

Push Down Method Verhalten einer Oberklasse ist nur für einige der Unterklassen relevant. Im Laufe der Zeit sind Unterklasse entstanden und ein Verhalten, dass einst in der Oberklasse definiert wurde ist nun nur noch in einigen Unterklasse relevant Mit dem Refactoring Extract Subclass wurde eine Unterklasse angelegt und einige Methoden gehören dorthin 01.02.2010 Advanced Software Engineering 61

Push Down Method Vorgehen Die Methode in allen Subklassen deklarieren und den Code hineinkopieren Methode aus Oberklasse löschen Kompilieren und testen Methode aus jeder Subklasse entfernen, die sie nicht benötigt Kompilieren und testen 01.02.2010 Advanced Software Engineering 62

Extract Interface Mehrere Klienten benutzen denselben Teil der Schnittstelle einer Klasse oder zwei Klassen haben einen Teil ihrer Schnittstellen gemeinsam. Zuständigkeiten von Klassen zerfallen oft in mehrere Bereiche. Oft ist es sinnvoll, diese einzelnen Bereiche als eigenständige Entitäten auszuzeichnen Programmieren gegen Interfaces besser als gegen Klassen, da so die Kopplung an änderbare Teile reduziert wird Interfaces erlauben eine schwache Mehrfachvererbung 01.02.2010 Advanced Software Engineering 63

Extract Interface Vorgehen Ein leeres Interface erstellen Alle gemeinsamen Operationen im neuen Interface deklarieren Alle relevanten Klassen als implementierende Klassen für das Interface deklarieren Typdeklarationen in den Klienten auf das neue Interface umstellen 01.02.2010 Advanced Software Engineering 64

Extract Interface Beispiel class Employee { public int getrate() { public boolean hasspecialskill() { double charge(employee emp, int days) { int base = emp.getrate() * days; if (emp.hasspecialskill()) return base * 1,05; else return base; 01.02.2010 Advanced Software Engineering 65

Extract Interface Beispiel interface Billable { public int getrate(); public boolean hasspecialskill(); class Employeee implements Billable { double charge(billable emp, int days) { int base = emp.getrate() * days; if (emp.hasspecialskill()) return base * 1,05; else return base; 01.02.2010 Advanced Software Engineering 66

Replace Magic Number with Symbolic Constant Im Code gibt es eine Zahlen-Literal mit einer spezifischen Bedeutung. Magic numbers machen jeden Code unverständlich und schlecht wartbar Änderungen an mehreren Orten erforderlich 01.02.2010 Advanced Software Engineering 67

Replace Magic Number with Symbolic Constant Vorgehen Eine Konstante deklarieren und auf den Wert der magic number setzen Alle Auftreten der magic number finden Prüfen, ob die Intention der magic number die Konstante ist. Wenn ja, ersetzen Kompilieren Wenn alle Auftreten der magic number ersetzt sind, kompilieren und testen 01.02.2010 Advanced Software Engineering 68

Replace Magic Number with Symbolic Constant Beispiel double potentialenergy(double mass, double height) { return mass * 9,81 * height; double potentialenergy(double mass, double height) { return mass * GRAVITATIONAL_CONSTANT * height; static final double GRAVITATIONAL_CONSTANT = 9,81; 01.02.2010 Advanced Software Engineering 69

Weitere Refactorings Es gibt noch viele, viele mehr www.refactoring.com 01.02.2010 Advanced Software Engineering 70

Literaturtipps M. Fowler: Refactoring Improving the Design of Existing Code; Addison-Wesley; 1999 R.C. Martin: Clean Code Refactoring, Patterns, Testen und Techniken für sauberen Code; mitp Verlag; 2009 Refactoring Home Page: http://www.refactoring.com/ Refactoring auf Wikipedia: http://de.wikipedia.org/wiki/refactoring 01.02.2010 Advanced Software Engineering 71