Μεθοδολογίες Προγραμματισμού ΙΙ Αναδόμηση Λογισμικού - 2 Software Refactoring - Εφαρμογές Παναγιώτης Σφέτσος, PhD
2Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ “Refactoring is a disciplined technique for restructuring an existing body of code, altering its internal structure without changing its external behavior “ (Martin Fowler): Γιατί αναδόμηση: Εύκολη προσθήκη νέου κώδικα Βελτίωση του σχεδιασμού του κώδικα Καλύτερη κατανόηση του κώδικα ‘Καθαρότερος’ κώδικας Συμπτώματα κακής σχεδίασης (1 ο σετ διαφάνειες): Αναδόμηση Κώδικα (Refactoring)
3Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ Το Eclipse αλλά και άλλα εργαλεία ανάπτυξης υποστηρίζουν την αναδόμηση κώδικα… Eclipse….
4Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ Γιατί; Βήματα: 1 - Ελέγχουμε αν η μέθοδος υλοποιείται από μια υπερκλάση ή υποκλάση. 2 - …… Μετονομασία μεθόδου
5Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ Γιατί; Περισσότερο χρήσιμη σε άλλη κλάση παρά σε αυτήν που αρχικά την τοποθετήσαμε.. Μετακίνηση μεθόδου - 1
6Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ class Account… double overdraftCharge() { if ( _type.isPremium()) { double result = 10; if (_dayOverdrawn > 7) result += (_daysOverdrawn – 7) * 0.85; return result; }// end if else return _daysOverdrawn * 1.75; } // end overdraftChrge double bankCharge () { double result = 4.5; if (_daysOverdrawn > 0) result += overdraftCharge(); return result; } // end bankCharge private AccountType _type; private int _daysOverdrawn; Μετακίνηση μεθόδου - 2 Αν θέλουμε άλλους τύπους λογαριασμών.. και θέλουμε να δημιουργήσουμε μια κλάση με λογαριασμούς που θα περιέχει τις μεθόδους…
7Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ Ελέγχουμε αν οι μέθοδοι είναι ίδιες. Αν όχι τις τροποποιούμε. Δημιουργούμε την μέθοδο στην υπερκλάση ………. Μετακίνηση μεθόδου – 3 (κληρονομικότητα) Advertiser + Address Player + Address LeagueOwner + Address PlayerAdvertiserLeagueOwner User + Address
8Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ public class Player { private String ; //... } public class LeagueOwner { private String ; //... } public class Advertiser { private String _address; //... } Μετακίνηση μεθόδου – 4 (κληρονομικότητα) public class User { private String ; } public class Player extends User { //... } public class LeagueOwner extends User { //... } public class Advertiser extends User { //... }
9Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ Μετακίνηση δομητή public class User { private String ; } public class Player extends User { public Player(String ) { this. = ; } public class LeagueOwner extends User{ public LeagueOwner(String ) { this. = ; } public class Advertiser extendsUser{ public Advertiser(String ) { this. = ; } Μετακίνηση δομητή – 5 (κληρονομικότητα) public class User { public User(String ) { this. = ; }} public class Player extends User { public Player(String ) { super( ); }} public class LeagueOwner extends User { public LeagueOwner(String ) { super( ); } } public class Advertiser extends User { public Advertiser(String ) { super( ); }}
10Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ Γιατί; Δύσκολη η συντήρηση του κώδικα Αλλαγές του κώδικα σε πολλά μέρη Ευκολία στο λάθος ‘Ακάθαρτος’ κώδικας Τεχνική: Αναδόμηση μέσω κληρονομικότητας Αναδόμηση μέσω κλήσεων αντικειμένων (delegation) Αναδόμηση επαναλαμβανόμενου κώδικα – 1
11Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ Μήπως κάποιος επαναλαμβανόμενος κώδικας; Αναδόμηση με κληρονομικότητα – 2 class A { void m1() { // … step1(); step2(); step3(); // … } // … } class B { void m2() { // … step1(); step2(); step3(); // … } // … }
12Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ Αναδόμηση με κληρονομικότητα – 3 class C { void computeAll() { step1(); step2(); step3(); } class A extends C { void m1() { // … computeAll(); // … } // … } class B extends C { void m2() { // … computeAll(); // … } // … }
13Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ Αναδόμηση μέσω κλήσεων – 4 class Helper { void computeAll() { step1(); step2(); step3(); } class A { void m1() { // … h.computeAll(); // … } Helper h; } class B { void m2() { // … h.computeAll(); // … } Helper h; }
14Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ Εξαγωγή Μεθόδου void printOwning(double amt) { printBanner(); System.out.println(“name” + name); System.out.println(“amount” + amt); } void printDetails(double amt) { System.out.println(“name” + name); System.out.println(“amount” + amt); } void printOwning(double amt) { printBanner(); printDetails(amt); }
15Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ Όταν το πεδίο χρησιμοποιείται περισσότερο σε μια κλάση απ’ότι στην αρχική. Μετακίνηση Πεδίου class AccountType…. private double _interestRate; void setInterestRate (double arg) { _interestRate = arg; } double getInterestRate () { return _interestRate; } ………. double interestForAccount_days (double amount, int days) { return _type.getInterestRate() * amount * days/365; } Μετακίνηση της _interestRate. ….χρήση των get() & set() μεθόδων για το πεδίο Στην αρχική κλάση…..
16Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ Όταν έχουμε πολλούς ελέγχους για μηδενική τιμή, τότε δημιουργούμε το μηδενικό αντικείμενο. Εισαγωγή του μηδενικού - αντικειμένου (1/2) Customer c = findCustomer(..);... if (customer == null) { name = “occupant”; } else { name = customer.getName(); } if (customer == null) { …
17Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ Δεν χρησιμοποιούμε πλέον τις εντολές – if, αλλά το μηδενικό-αντικείμενο κάνει πλέον τους ελέγχους. Εισαγωγή του μηδενικού - αντικειμένου (2/2) public class NullCustomer extends Customer { public String getName() { return “occupant”; } Customer c = findCustomer(); name = c.getName();
18Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ Δεν χρησιμοποιούμε την εντολή – switch, αλλά υπερκλάση που την επεκτείνουμε… Αντικατάσταση των εντολών switch (1/2) class Animal { final int MAMMAL = 0, BIRD = 1, REPTILE = 2; int myKind; // set in constructor... String getSkin() { switch (myKind) { case MAMMAL: return "hair"; case BIRD: return "feathers"; case REPTILE: return "scales"; default: return "integument"; } } }
19Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ Τι θα γίνει αν χρειαστεί νέα προσθήκη; Αντικατάσταση των εντολών switch (2/2) class Animal { String getSkin() { return "integument"; } } class Mammal extends Animal { String getSkin() { return "hair"; } } class Bird extends Animal { String getSkin() { return "feathers"; } } class Reptile extends Animal { String getSkin() { return "scales"; } }
20Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ Παράδειγμα από το βιβλίο του Fowler: Αντικατέστησε : double basePrice = quantity * itemPrice; if (basePrice > 1000) return basePrice * 0.95; else return basePrice * 0.98; Με τον κώδικα: if (basePrice() > 1000) return basePrice() * 0.95; else return basePrice() * 0.98;... double basePrice() { return quantity * itemPrice; } Αντικατάσταση temp. μεταβλητής με μέθοδο
21Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ Όταν έχουμε πολλές παραμέτρους σε μια μέθοδο: Αντικατέστησε : public void marry(String name, int age, boolean gender, String name2, int age2, boolean gender2) {...} Με τον κώδικα: public void marry(Person person1, Person person2) {..} Δημιουργία αντικειμένου - παραμέτρων
22Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ Όταν έχουμε πολλές παραμέτρους του ίδιου αντικειμένου σε μια μέθοδο: Αντικατέστησε : sendBill(customer.name, customer.address, customer.order, amount); Με τον κώδικα: sendBill(customer, amount); Παρουσίαση αντικειμένου - παραμέτρων