Η παρουσίαση φορτώνεται. Παρακαλείστε να περιμένετε

Η παρουσίαση φορτώνεται. Παρακαλείστε να περιμένετε

Refactoring Επανασχεδίαση, Αναδόμηση, Επαναπαραγοντοποίηση Μεταπτυχιακό Πρόγραμμα Σπουδών, Τμ. Εφ. Πληροφορικής.

Παρόμοιες παρουσιάσεις


Παρουσίαση με θέμα: "Refactoring Επανασχεδίαση, Αναδόμηση, Επαναπαραγοντοποίηση Μεταπτυχιακό Πρόγραμμα Σπουδών, Τμ. Εφ. Πληροφορικής."— Μεταγράφημα παρουσίασης:

1 Refactoring Επανασχεδίαση, Αναδόμηση, Επαναπαραγοντοποίηση Μεταπτυχιακό Πρόγραμμα Σπουδών, Τμ. Εφ. Πληροφορικής

2 Refactoring Αναδόμηση είναι η διαδικασία τροποποίησης του λογισμικού κατά τέτοιο τρόπο ώστε να μην αλλάζει η εξωτερική συμπεριφορά του κώδικα να βελτιώνεται η εσωτερική δομή του Είναι ένα συστηματικός τρόπος "καθαρισμού" (clean up) του κώδικα ο οποίος ελαχιστοποιεί τις πιθανότητες εισαγωγής σφαλμάτων Στην πράξη, με την αναδόμηση, βελτιώνεται η σχεδίαση αφού έχει ήδη γραφεί ο κώδικας !! Συνήθως προηγείται η καλή σχεδίαση και ακολουθεί η υλοποίηση του κώδικα Ωστόσο, με την πάροδο του χρόνου, η αρχική σχεδίαση εκφυλίζεται Η αναδόμηση είναι η αντίστροφη διαδικασία: Λαμβάνεται μία κακή σχεδίαση και αναδομείται για να προκύψει καλά σχεδιασμένος κώδικας

3 Refactoring Τα βήματα που εμπλέκονται στη διαδικασία είναι απλά – ίσως απλοϊκά Όμως, το αθροιστικό αποτέλεσμα των βημάτων αλλάζει δραστικά τη σχεδίαση

4 Refactoring Παράδειγμα: Πρόγραμμα υπολογισμού και εκτύπωσης της χρέωσης ενός πελάτη σε ένα video club. Το πρόγραμμα λαμβάνει ως είσοδο τις ταινίες που ενοικιάστηκαν και τη διάρκεια ενοικίασης. Στη συνέχεια υπολογίζει τη χρέωση βάσει της διάρκειας και του τύπου (regular, children's, new_releases). Επίσης υπολογίζονται πόντοι συχνής ενοικίασης. Διάγραμμα Ακολουθίας ->

5 Refactoring

6 Σχόλια επί του αρχικού προγράμματος : Το πρόγραμμα δουλεύει ("there is nothing wrong with a quick and dirty program") Η μέθοδος statement στην κλάση Customer κάνει πάρα πολλά Ένα κακώς σχεδιασμένο σύστημα αλλάζει με δυσκολία: Εκτύπωση σε HTML ? Αδύνατη η επαναχρησιμοποίηση κώδικα της statement Μόνη λύση, η δημιουργία νέας μεθόδου με cut and paste και αλλαγές και αν αλλάξουν οι κανόνες χρέωσης ?? …. αλλαγές και στις 2 μεθόδους αν αλλάξει ο τρόπος κατηγοριοποίησης ταινιών ?? που θα πρέπει να γίνουν οι αλλαγές ?? 2 μέθοδοι εκτύπωσης πρέπει να παραμείνουν συμβατές Tip: Αν θέλετε να προσθέσετε ένα νέο χαρακτηριστικό σε ένα πρόγραμμα και ο κώδικας δεν είναι δομημένος ώστε να προστεθεί εύκολα, πρώτα αναδομήστε το λογισμικό και μετά προσθέστε το χαρακτηριστικό

7 Refactoring Βήμα 1ο: Δημιουργία ελέγχων 1.Αποσύνθεση και ανακατανομή της λειτουργικότητας της statement() Refactoring: Extract Method Έχετε ένα τμήμα κώδικα που μπορεί να ομαδοποιηθεί Μετατρέψτε το τμήμα σε συνάρτηση το όνομα της οποίας εξηγεί τη λειτουργία Στην statement απομονώνουμε την εντολή switch Τοπικές Μεταβλητές: each, thisAmount each : δεν τροποποιείται και κατά συνέπεια περνά ως παράμετρος thisAmount: τροποποιείται και πρέπει να επιστραφεί η τιμή της Εφαρμογή και Έλεγχος…….

8 Refactoring Αλλαγή ονομάτων στη νέα μέθοδο: each -> aRental thisAmount -> result "Any fool can write code that a computer can understand. Good programmers write code that humans can understand"

9 Refactoring Refactoring: Move Method Μία μέθοδος χρησιμοποιείται, ή θα χρησιμοποιηθεί σε περισσότερα σημεία μιας άλλης κλάσης από ότι αυτή στην οποία ορίζεται Δημιουργείστε μία νέα μέθοδο με παρόμοιο σώμα στη κλάση όπου χρησιμοποιείται περισσότερο. Είτε μετατρέψτε την παλιά μέθοδο σε απλή αποστολή μηνύματος (delegation) είτε απομακρύνετε την τελείως Η μέθοδος amountFor χρησιμοποιεί πληροφορία από την Rental αλλά όχι από την Customer Μετακίνησή της ως getCharge() στην κλάση Rental Εφαρμογή και Έλεγχος……. Προσοχή: Τροποποίηση της Customer να καλεί τη νέα μέθοδο thisAmount = each.getCharge() Διαγραφή της παλιάς μεθόδου

10 Refactoring

11 Στην κλάση Customer η μεταβλητή thisAmount δεν χρειάζεται πλέον Refactoring: Replace Temp with Query Χρησιμοποιείτε μία προσωρινή μεταβλητή για να κρατήσετε το αποτέλεσμα ενός υπολογισμού Εξάγετε τον υπολογισμό σε μία μέθοδο. Αντικαταστήστε όλες τις αναφορές στην προσωρινή μεταβλητή με κλήσης της μεθόδου Αντικατάσταση των thisAmount με each.getCharge() Εφαρμογή και Έλεγχος…….

12 Refactoring Παρόμοια διαδικασία για τους πόντους συχνής ενοικίασης Refactoring: Extract Method Refactoring: Move Method (από Customer στην κλάση Rental) Εφαρμογή και Έλεγχος…….

13 Refactoring Πριν ….

14 Refactoring Μετά ….

15 Refactoring Οι προσωρινές μεταβλητές μπορεί να αποτελέσουν πρόβλημα: Χρησιμοποιούνται μόνο μέσα στη δική τους ρουτίνα και ενθαρρύνουν την ανάπτυξη μεγάλων μεθόδων Στην κλάση Customer (μέθοδος statement) υπάρχουν 2 προσωρινές μεταβλητές. Refactoring: Replace Temp with Query (totalAmount, frequentRenterPoints) Αντικατάσταση της totalAmount με μέθοδο getTotalCharge private double getTotalCharge() { double result = 0; Enumeration rentals = _rentals.elements(); while(rentals.hasMoreElements()) { Rental each = (Rental) rentals.nextElement(); result += each.getCharge(); } return result; }

16 Refactoring Αντικατάσταση της frequentRenterPoints με μέθοδο getTotalFrequentRenterPoints private double getTotalFrequentRenterPoints() { int result = 0; Enumeration rentals = _rentals.elements(); while(rentals.hasMoreElements()) { Rental each = (Rental) rentals.nextElement(); result += each.getFrequentRenterPoints(); } return result; }

17 Refactoring Πριν ….

18 Refactoring Μετά ….

19 Refactoring Άξιζε η τελευταία αναδόμηση ? Οι περισσότερες μειώνουν τον κώδικα, αυτή τον αύξησε Ο προηγούμενος κώδικας εκτελούσε το βρόχο μία φορά, τώρα τον εκτελεί τρείς Οι μέθοδοι που προστέθηκαν (queries) είναι πλέον διαθέσιμες σε οποιαδήποτε λειτουργικότητα γραφεί πλέον στην κλάση Customer. Μπορούν εύκολα να προστεθούν στη διασύνδεση της κλάσης αν τις χρειαστούν και άλλα τμήματα του συστήματος. Η διαφορά είναι εμφανής με την υλοποίηση της htmlStatement

20 Refactoring public String htmlStatement() { Enumeration rentals = _rentals.elements(); String result = " Rental Record for " + getName() + " \n"; while(rentals.hasMoreElements()) { Rental each = (Rental) rentals.nextElement(); result += each.getMovie().getTitle() + String.valueOf(each.getCharge()) + " \n"; } result += " Amount owed is " + String.valueOf(getTotalCharge()) + " \n"; result += "You earned " + String.valueOf(getTotalFrequentRenterPoints()) + " frequent renter points"; return result; }

21 Refactoring Πλέον η επαναχρησιμοποίηση είναι φανερή: Αν αλλάξουν οι κανόνες χρέωσης θα χρειαστεί να τροποποιηθεί μόνο ένα τμήμα κώδικα Θα μπορούσαν να εξαχθούν και άλλα τμήματα της statement μεθόδου σε ξεχωριστές μεθόδους Τι θα γίνει αν αλλάξει η κατηγοριοποίηση των ταινιών ή προσθέσουν νέες κατηγορίες στο μέλλον ? Θα απαιτείται κάθε φορά τροποποίηση των μεθόδων υπολογισμού χρέωσης και πόντων και του κώδικα ελέγχου σε αυτές

22 Refactoring Αντικατάσταση της Λογικής Ελέγχου Συνθηκών στην Τιμή με Πολυμορφισμό Η εντολή switch είναι προβληματική: Είναι κακή ιδέα να εκτελείται switch εντολή βασισμένη στις ιδιότητες κάποιου άλλου αντικειμένου Αν πρέπει να χρησιμοποιηθεί εντολή switch θα πρέπει να είναι στα δικά σας δεδομένα, όχι κάποιου άλλου

23 Refactoring Η μέθοδος getCharge θα πρέπει να μετακινηθεί από την Rental στην Movie: class Movie … double getCharge(int daysRented) { double result = 0; switch(getPriceCode()) { case Movie.REGULAR: result += 2; if (getDaysRented() > 2) result += (getDaysRented() – 2) * 1.5; break;...

24 Refactoring Πρέπει ωστόσο να περάσει η διάρκεια ενοικίασης ως παράμετρος Γιατί προτιμούμε να περάσουμε τη διάρκεια ενοικίασης στην Movie αντί του τύπου της ταινίας στην Rental ? Διότι οι αναμενόμενες αλλαγές είναι αλλαγές τύπων: Η πληροφορία τύπων είναι γενικά πιο ευάλωτη σε αλλαγές H getCharge στην Rental τροποποιείται ώστε να χρησιμοποιεί τη νέα μέθοδο class Rental... double getCharge() { return _movie.getCharge(_daysRented); } Εφαρμογή και Έλεγχος…….

25 Refactoring Πριν … Μετα …

26 Refactoring Ίδια αλλαγή με την getFrequentRenterPoints() ….. Εφαρμογή και Έλεγχος…….

27 Refactoring τέλος…. Κληρονομικότητα έχουμε πολλές κατηγορίες ταινιών που "απαντούν" στο ίδιο ερώτημα. Αυτό "μυρίζει" κληρονομικότητα έτσι θα μπορούσαμε να αντικαταστήσουμε τους ελέγχους με πολυμορφισμό Ωστόσο, μία ταινία μπορεί να αλλάξει κατηγορία (ενώ ένα αντικείμενο δεν μπορεί να αλλάξει κλάση κατά τη διάρκεια ζωής του)

28 Refactoring Λύση: Πρότυπο State

29 Refactoring Απαιτούνται 3 αναδομήσεις Refactoring: Replace Type Code with State/Strategy (απαιτείται αλλαγή στην Movie για να μπορεί να αλλάζει η τιμή) public Movie(String title, int priceCode) { _title = title; _priceCode = priceCode; } -------------------------------- public Movie(String title, int priceCode) { _title = title; setPriceCode(priceCode); }

30 Refactoring Προσθήκη νέας abstract κλάσης Price και υποκλάσεων public abstract class Price { abstract int getPriceCode(); abstract double getCharge(int daysRented); } class ChildrensPrice extends Price { int getPriceCode() { return Movie.CHILDRENS; } Εφαρμογή και Έλεγχος…….

31 Refactoring Τροποποιήσεις στην Movie ώστε να προσπελαύνουν τη νέα θέση της πληροφορίας που αφορά τον τύπο

32 Refactoring public int getPriceCode() { return _price.getPriceCode(); } 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"); } } private Price _price; Εφαρμογή και Έλεγχος…….

33 Refactoring Refactoring: Move Method η getCharge από την Movie στην Price class Movie... double getCharge(int daysRented) { return _price.getCharge(daysRented); } -------------------------------- class Price... double getCharge(int daysRented) { double result = 0; switch(getPriceCode()) { case....

34 Refactoring Refactoring: Replace Conditional with Polymorphism κάθε τμήμα της switch μεταφέρεται σε υπερφορτωμένη μέθοδο των υποκλάσεων class Price... double getCharge(int daysRented) { double result = 0; switch(getPriceCode()) { case Movie.REGULAR: result += 2; if(daysRented > 2) result += (daysRented – 2) * 1.5; break;

35 Refactoring Στην κλάση RegularPrice… class RegularPrice... double getCharge(int daysRented) { double result = 2; if (daysRented > 2) result += (daysRented - 2) * 1.5; retun result; }

36 Refactoring Όταν γίνει το ίδιο για όλες τις υποκλάσεις, η getCharge στην Price δηλώνεται αφηρημένη Οποιαδήποτε πλέον αλλαγή στην κατηγοριοποίηση των κλάσεων το υπόλοιπο σύστημα δεν χρειάζεται καν να ενημερωθεί.

37 Refactoring


Κατέβασμα ppt "Refactoring Επανασχεδίαση, Αναδόμηση, Επαναπαραγοντοποίηση Μεταπτυχιακό Πρόγραμμα Σπουδών, Τμ. Εφ. Πληροφορικής."

Παρόμοιες παρουσιάσεις


Διαφημίσεις Google