αναδομηση λογισμικου

Download Report

Transcript αναδομηση λογισμικου

Μεθοδολογίες Προγραμματισμού ΙΙ

Αναδόμηση Λογισμικού Software Refactoring

Παναγιώτης Σφέτσος, PhD http://aetos.it.teithe.gr/~sfetsos/ [email protected]

Σχεδίαση

Στη

σχεδίαση ενός έργου λογισμικού

επιδιώκεται η:

   Αποσύνθεση του συστήματος σε τμήματα Ανάθεση αρμοδιοτήτων σε κάθε τμήμα Επικύρωση ότι όλα τα τμήματα μαζί επιτυγχάνουν τους σκοπούς του συστήματος.

Γραφική

αναπαράσταση του συστήματος,

συνήθως με διαγράμματα UML.

Tο σύστημα θα πρέπει να

επεκτείνεται

και να

τροποποιείται

εύκολα με μικρή προσπάθεια.

Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ 2

Συμπτώματα "κακής" σχεδίασης

       Δυσκαμψία (Rigidity): Το σύστημα είναι δύσκολο να τροποποιηθεί διότι κάθε αλλαγή οδηγεί σε πληθώρα αλλαγών σε άλλα τμήματα του συστήματος.

Ευθραυστότητα (Fragility): Οι αλλαγές που πραγματοποιούνται στο λογισμικό προκαλούν σφάλματα σε διάφορα σημεία. Ακινησία (Immobility): Υπάρχει δυσκολία διαχωρισμού του συστήματος σε συστατικά τα οποία μπορούν να επαναχρησιμοποιηθούν σε άλλες εφαρμογές. Έλλειψη ρευστότητας (Viscosity): Η πραγματοποίηση τροποποιήσεων με λάθος τρόπο είναι ευκολότερη από την πραγματοποίησή τους με τον ορθό τρόπο.

Περιττή Πολυπλοκότητα (Needless Complexity): που δεν είναι (ούτε πρόκειται να γίνουν) χρήσιμα. Το λογισμικό περιλαμβάνει στοιχεία Περιττή Επανάληψη (Needless Repetition): Η σχεδίαση περιλαμβάνει επαναλαμβανόμενες δομές που θα μπορούσαν να ενοποιηθούν υπό μία κοινή αφαίρεση.

Αδιαφάνεια (Opacity): κώδικα). Δυσκολία κατανόησης μιας μονάδας (σε επίπεδο σχεδίου ή Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ 3

Λύση

Στην εμφάνιση κάποιου

συμπτώματος κακής σχεδίασης:

Οφείλουμε να λάβουμε υπόψη

κάποιες βασικές αρχές σχεδίασης

και να προβούμε σε κάποιες

επεμβάσεις στο λογισμικό.

Η δραστηριότητα αυτή ονομάζεται

αναδόμηση(Refactoring)

Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ 4

Αρχές Αντικειμενοστρεφούς Σχεδίασης

       Αρχή της Ανοικτής-Κλειστής Σχεδίασης (

Open-Closed Principle

- OCP) Αρχή της Ενσωμάτωσης Αρχή της Χαμηλής Σύζευξης Αρχή της Μοναδικής Αρμοδιότητας (

Single Responsibility Principle

- SRP) Αρχή της Υποκατάστασης της Liskov (

Liskov Substitution Principle

- LSP) Αρχή της Αντιστροφής των Εξαρτήσεων (

Dependency Inversion Principle

- DIP) Αρχή του Διαχωρισμού των Διασυνδέσεων (

Interface Segregation Principle

- ISP)  Οι ανωτέρω αρχές είναι προϊόν εμπειρίας δεκαετιών στην τεχνολογία λογισμικού.

 Προτείνονται ως θεραπεία σε κάποιο σύμπτωμα που έχει ήδη διαπιστωθεί.

Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ 5

Αρχή της Ανοικτής-Κλειστής Σχεδίασης

(1/6)

Οι οντότητες λογισμικού (κλάσεις, μονάδες, συναρτήσεις, κλπ) θα πρέπει να είναι ανοικτές για επέκταση, αλλά κλειστές για τροποποίηση.

  

Ανοικτές για επέκταση:

Η συμπεριφορά της μονάδας μπορεί να επεκταθεί.

Κλειστές για τροποποίηση:

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

Η αρχή της Ανοικτής-Κλειστής Σχεδίασης θεραπεύει τα

συμπτώματα της δυσκαμψίας και ευθραυστότητας.

 Η αφαίρεση (abstraction) και ο πολυμορφισμός (polymorphism) είναι η λύση.

Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ 6

Αρχή της Ανοικτής-Κλειστής Σχεδίασης

(2/6) Η κλάση Painter

δεν συμμορφώνεται

με την αρχή της Ανοικτής-Κλειστής Σχεδίασης, γιατί δεν μπορεί να "κλειστεί" έναντι νέων τύπων σχημάτων. Αν θέλαμε να επεκτείνουμε την κλάση ώστε να περιελάμβανε και τρίγωνα, θα έπρεπε να τροποποιήσουμε τον κώδικα της κλάσης. Γενικότερα, η κλάση πρέπει να τροποποιείται για κάθε νέο τύπο σχήματος που προστίθεται (ο κώδικας Java στο βιβλίο).

Παραβίαση της αρχής Ανοικτής-Κλειστής Σχεδίασης

Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ 7

Αρχή της Ανοικτής-Κλειστής Σχεδίασης

(3/6) Η λύση με την

αφαίρεση

και τον

πολυμορφισμό.

Μια νέα

αφηρημένη κλάση Shape

προστίθεται στο σύστημα και ενσωματώνει οτιδήποτε μπορεί να μεταβληθεί, δηλαδή τη μέθοδο σχεδίασης οποιουδήποτε σχήματος. Η αφηρημένη κλάση ορίζει μια

αφηρημένη μέθοδο draw()

, ενώ οποιοδήποτε σχήμα είναι

παράγωγη κλάση της Shape

και υλοποιεί ανάλογα τη μέθοδο draw(). Η κλάση Painter

δεν χρειάζεται να τροποποιηθεί

και κατά συνέπεια συμμορφώνεται με την αρχή της Ανοικτής- Κλειστής Σχεδίασης (ο κώδικας Java στο βιβλίο).

Συμμόρφωση με την αρχή Ανοικτής-Κλειστής Σχεδίασης

Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ 8

Αρχή της Ανοικτής-Κλειστής Σχεδίασης

(4/6)

Παράδειγμα:

 Πως θα κάνουμε το αυτοκίνητο να τρέξει με μία ‘τούρμπο’ μηχανή; Στην παρακάτω σχεδίαση, αλλάζοντας την Car

(Κακή σχεδίαση).

Η συμπεριφορά της μονάδας μπορεί να επεκταθεί δημιουργώντας νέες υποκλάσεις της αφαίρεσης

(Καλή σχεδίαση).

Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ 9

Αρχή της Ανοικτής-Κλειστής Σχεδίασης

(5/6)

Παράδειγμα: Παραβίαση OCP:

Τι θα γίνει αν ο πελάτης θελήσει να αλλάξει server; Client Server

Συμμόρφωση με OCP :

Σχεδιαστικό πρότυπο STRATEGY Client «interface»

ClientInterface

Server Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ 10

Αρχή της Ανοικτής-Κλειστής Σχεδίασης

(6/6)

Εναλλακτική δομή:

Σχεδιαστικό πρότυπο TEMPLATE METHOD.

Η

συμπεριφορά

που προσδιορίζεται μέσα στην κλάση

Policy

μπορεί να επεκταθεί δημιουργώντας νέες υποκλάσεις της, χωρίς να απαιτείται τροποποίηση του πηγαίου κώδικα της.

Policy

+PolicyFunction() -ServiceFunction()

Implementation

-ServiceFunction()  Τα δύο αυτά πρότυπα είναι οι

συνηθέστεροι τρόποι συμμόρφωσης

με την αρχή OCP.

Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ 11

Αρχή της Ενσωμάτωσης

(1/4) Αρχή της Ενσωμάτωσης ή αρχή της ενθυλάκωσης (Encapsulation Principle): Η εσωτερική κατάσταση ενός αντικειμένου πρέπει να είναι τροποποιήσιμη μόνο μέσω της δημόσιας διασύνδεσης του.

  Oι ιδιότητες

δεν πρέπει να είναι προσπελάσιμες

εκτός της κλάσης

(ορατότητα private)

αλλά η τροποποίηση των τιμών των θα γίνεται μόνο μέσω των

δημοσίων μεθόδων

.

Συνήθως εφαρμόζεται ακόμα και αν δεν συνειδητοποιείται η χρησιμότητα. , Αντικείμενο1 : Λογαριασμός κατάσταση  - όνομα_κατόχου - αριθμός - υποκατάστημα_Τράπεζας - υπόλοιπο συμπεριφορά  + υπολογισμός_Τόκων( ) + εκτύπωση_Υπολοίπου( ) + κατάθεση( ) + ανάληψη( ) πρόσβαση στις ιδιότητες μόνο μέσω των δημόσιων μεθόδων Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ 12

Αρχή της Ενσωμάτωσης

(2/4) Παράδειγμα: class EncapTest{ private

String name;

private

String idNum; Μόνο μέσω των δημοσίων μεθόδων

setters

τα ιδιωτικά πεδία.

και

getters

μπορούν να προσπελαθούν

private public public

void setName(String newName) {name = newName;}

public public public

int age; void setAge( int newAge) {age = newAge; } void setIdNum( String newId) {idNum = newId;} int getAge() {return age; } String getName() {return name; } •

Πλεονεκτήματα:

Τα πεδία γίνονται

read only

ή

write-only

.

• Μόνο η κλάση έχει τον απόλυτο έλεγχο των δεδομένων των πεδίων.

• Οι χρήστες της κλάσης δεν γνωρίζουν πως αυτή αποθηκεύει τα δεδομένα της.

public

String getIdNum() {return idNum; }} Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ 13

Αρχή της Ενσωμάτωσης

(3/4) public class TestEncap{ public static void main(String args[]){

EncapTest encap = new EncapTest(); encap.setName("Nikas Nikos"); encap.setAge(30); encap.setIdNum("0623457"); System.out.println("Name : " + encap.getName()); System.out.println("Age : "+ encap.getAge());

} }

Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ 14

Αρχή της Ενσωμάτωσης

(4/4) Συμπερασματικά:

• Η παραβίαση της αρχής μπορεί να προκαλέσει ορισμένα από τα σημαντικότερα προβλήματα.

• Επιτρέποντας την τροποποίηση των τιμών των ιδιοτήτων

καταργείται η ομαδοποίηση δεδομένων και συμπεριφοράς.

• Στη συνέχεια θα είναι δύσκολο να εντοπιστούν

ποια τμήματα κώδικα επηρεάζουν ποια δεδομένα

.

Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ 15

Αρχή της Χαμηλής Σύζευξης

(1/3) Αρχή της Χαμηλής Σύζευξης: Σε ένα σχέδιο λογισμικού πρέπει να επιδιώκεται η επίτευξη της μικρότερης δυνατής σύζευξης μεταξύ των συστατικών του.

Πλεονεκτήματα:

 Ανεξαρτησία μεταξύ των συστατικών

(τεχνικές της αφαίρεσης και της απόκρυψης πληροφορίας).

 Ευκολότερη η υλοποίηση, ο έλεγχος και η συντήρηση του λογισμικού.

 Ευκολότερη η κατανομή του έργου σε διαφορετικούς προγραμματιστές και ευκολότερος ο εντοπισμός των σφαλμάτων.

Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ 16

Αρχή της Χαμηλής Σύζευξης

(2/3)

• •

Παράδειγμα κακής σχεδίασης (υψηλή σύζευξη):

Αν

τροποποιηθεί

η

Χρονόμετρο

απαιτείται ο έλεγχος και ενδεχομένως η μεταγλώττιση των συσχετιζόμενων κλάσεων.

Για να

επαναχρησιμοποιηθεί

η

Χρονόμετρο

της προς τις συσχετιζόμενες κλάσεις.

απαιτείται “μεταφορά” των αναφορών Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ 17

Αρχή της Χαμηλής Σύζευξης

(3/3)

 Δύσκολη η επίτευξη της μείωσης της σύζευξης. Μετράται εύκολα με την

μετρική

CBO (Coupling between Objects) των Chidamber & Kemerer, 1994.

Η τιμή της μετρικής για μια κλάση Α ισούται με τον αριθμό των άλλων κλάσεων με τις ποίες υπάρχει σύζευξη. Ως σύζευξη θεωρείται:

 η χρήση μεθόδων  η απευθείας πρόσβαση σε μέλη δεδομένων  

Επίσης έχει προταθεί να θεωρείται ως σύζευξη:

 η χρήση τύπων μιας κλάσης ως παραμέτρων σε μεθόδους  η δημιουργία αντικειμένων η ύπαρξη φιλικών κλάσεων η αποστολή μηνυμάτων κατά τον χρόνο εκτέλεσης, κλπ.

Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ 18

Αρχή της Μοναδικής Αρμοδιότητας

(1/6)

Single Responsibility Principle

(SRP)

, Tom De Marco (1979): Συνεκτικότητα

(Cohesion)

Αρχή της Μοναδικής Αρμοδιότητας: Μια κλάση πρέπει να έχει μόνο ένα λόγο να αλλάξει.

 Κάθε κλάση δεν πρέπει να έχει περισσότερες από μία αρμοδιότητες (axis of change) Στο παράδειγμα (…ο κώδικας στο βιβλίο) : Η κλάση Shape περιλαμβάνει

λειτουργικότητα

που αφορά τη γραφική διασύνδεση χρήστη (μέθοδος draw()) και λειτουργικότητα (μέθοδοι getXLowerRightCorner() και getYLowerRightCorner()). Η συμπερίληψη και των δύο αρμοδιοτήτων στην ίδια κλάση ενδέχεται να οδηγήσει σε προβλήματα (αλλαγή στη μία επιφέρει αλλαγή και στην άλλη).

Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ 19

Αρχή της Μοναδικής Αρμοδιότητας

(2/6)

Η εφαρμογή της αρχής SRP επιβάλλει το διαχωρισμό των δύο αρμοδιοτήτων σε

δύο τελείως διαφορετικές κλάσεις.

Μετακινείται

η

λειτουργικότητα,

που αφορά τις γεωμετρικές εφαρμογές μηχανολογικού σχεδιασμού,

σε μια διαφορετική κλάση

η οποία δέχεται το αντικείμενο Shape ως παράμετρο στον κατασκευαστή της. Οι αλλαγές που γίνονται στη σχεδίαση των σχημάτων δεν μπορούν να επηρεάσουν την εφαρμογή μηχανολογικού σχεδιασμού. Η

συνεκτικότητα

των δύο κλάσεων GeometricShape και Shape είναι πολύ υψηλή, καθώς οι λειτουργίες τους εξυπηρετούν έναν και μόνο σκοπό σε κάθε κλάση.

Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ 20

Αρχή της Μοναδικής Αρμοδιότητας

(3/6)

Ποσοτικοποίηση του βαθμού συνεκτικότητας μιας κλάσης: Μετρική LCOM (Lack of Cohesion between Methods) των Chidamber & Kemerer, 1994.

Παίρνουμε κάθε ζευγάρι μεθόδων σε μια κλάση. Αν μοιράζονται

ασύνδετα σύνολα μεταβλητών

αυξάνουμε το P κατά 1 (καμία κοινή μεταβλητή). Αν μοιράζονται τουλάχιστον μια μεταβλητή, τότε αυξάνουμε το Q κατά 1.

LCOM1 = P – Q

(αν

P > Q),

διαφορετικά

LCOM1 = 0

  LCOM1 = 0,

σημαίνει συνεκτική κλάση

.

LCOM1 > 0, σημαίνει ότι η κλάση

πρέπει να ‘σπάσει’

σε δύο ή περισσότερες κλάσεις, καθότι οι μεταβλητές τους ανήκουν σε διαφορετικά σύνολα.

 Κατά συνέπεια, όσο μεγαλύτερη η συνεκτικότητα, τόσο μικρότερη η τιμή της LCOM .

Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ 21

Αρχή της Μοναδικής Αρμοδιότητας

(4/6)

Μια αρμοδιότητα ορίζεται ως μια "αιτία αλλαγών".

Πως μπορεί να εντοπισθεί; interface DataStructure

{

public void add(Object o); public void remove(Object o); public void write(OutputStream out); public void read(InputStream in);}

Οι αρμοδιότητες που υπάρχουν εδώ είναι δύο (διαχείριση των στοιχείων της δομής και η δυνατότητα αποθήκευσης και ανάκτησης των στοιχείων).

Θα πρέπει αυτές να διαχωριστούν;

Η απάντηση:

εξαρτάται από τον τρόπο με τον οποίο αλλάζει η εφαρμογή.

Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ 22

Αρχή της Μοναδικής Αρμοδιότητας

(5/6)

Αν η εφαρμογή

αλλάζει συχνά

κατά τέτοιο τρόπο ώστε να

τροποποιείται η υπογραφή των μεθόδων

προσθήκης/διαγραφής στοιχείων, τότε εμφανίζεται δυσκαμψία καθώς οι κλάσεις που καλούν τις μεθόδους αποθήκευσης/ανάκτησης θα πρέπει κάθε φορά να

επανα μεταγλωττίζονται

και να

ελέγχονται

εκ νέου. Σε αυτή την περίπτωση οι δύο αρμοδιότητες θα πρέπει να διαχωριστούν. Οι εφαρμογές που χρησιμοποιούν είτε τη διασύνδεση DataStructure, είτε τη διασύνδεση Storable

αποσυνδέονται μεταξύ τους

.

Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ 23

Αρχή της Μοναδικής Αρμοδιότητας

(6/6)

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

αλλαγές συμβαίνουν πράγματι

.

Συμπερασματικά:

 Η αρχή της Μοναδικής Αρμοδιότητας είναι ενδεχομένως η απλούστερη αρχή αντικειμενοστρεφούς σχεδίασης αλλά είναι και μία από τις δυσκολότερες να εφαρμοστεί.  Ο συγκερασμός αρμοδιοτήτων είναι κάτι που κάνουμε κατά φυσικό τρόπο. Ο εντοπισμός και ο διαχωρισμός αυτών των αρμοδιοτήτων αποτελεί κατά πολλούς ένα ουσιαστικό κομμάτι της σχεδίασης και ανάπτυξης λογισμικού.  Οι περισσότερες από τις αρχές και τους κανόνες που θα συζητηθούν στη συνέχεια σχετίζονται με τον ένα ή άλλο τρόπο με την αρχή SRP. Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ 24

Αρχή της Υποκατάστασης της Liskov

(1/6)

Αρχή Υποκατάστασης της Liskov (Barbara Liskov MIT, 1988):

Οι παράγωγοι τύποι πρέπει να μπορούν να υποκαθιστούν τους βασικούς τους τύπους.

     Η B δημόσια κληρονομεί (“is-a”) από την A, σημαίνει ότι Κάθε αντικείμενο τύπου Β είναι επίσης αντικείμενο του τύπου Α, σημαίνει Ότι είναι αληθές για το αντικείμενο Α είναι επίσης αληθές για το αντικείμενο Β.

Η Α αντιπροσωπεύει μια πιο γενική έννοια, ενώ η Β μια πιο ειδική.

Όπου μπορεί να χρησιμοποιηθεί ένα αντικείμενο του τύπου Α, μπορεί να χρησιμοποιηθεί ένα αντικείμενο του τύπου Β (υποκατάσταση).

Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ 25

Αρχή της Υποκατάστασης της Liskov

(2/6)

 Η αρχή αυτή είναι μια επέκταση της αρχής της Ανοικτής-Κλειστής Σχεδίασης και σημαίνει ότι πρέπει να είμαστε σίγουροι ότι οι

υποκλάσεις επεκτείνουν την βασική κλάση χωρίς να αλλοιώνουν την συμπεριφορά της.

 Με άλλα λόγια αν μια μονάδα προγράμματος αναφέρεται στη βασική κλάση, τότε πρέπει να μπορεί να την αντικαταστήσει με μια αναφορά στην υποκλάση της,

χωρίς να επηρεάζεται η λειτουργικότητα του προγράμματος.

Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ 26

Αρχή της Υποκατάστασης της Liskov

(3/6)

Έστω μία συνάρτηση ή μέθοδος:

m

(A ref), if

m

(B ref)

συμπεριφέρεται λάθος, όπου B υποκλάση της A, τότε η Β παραβιάζει την αρχή LSP.

Λύση: Έλεγχος μέσα στην m αν περνά ως όρισμα αντικείμενο τύπου Β.

Τότε παραβιάζεται η αρχή OCP.

Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ 27

Αρχή της Υποκατάστασης της Liskov

(4/6) Παράδειγμα παραβίασης της αρχής LSP:

Έστω η κλάση Square είναι υποκλάση της Rectangle και ότι η κλάση Square επιστρέφεται από ένα factory σύμφωνα με κάποιες συνθήκες. Δεν γνωρίζουμε τον τύπο του επιστρεφό μενου αντικειμένου αλλά ξέρουμε ότι είναι τύπου Rectangle. Ορίζουμε μήκος πλευράς = 4 και ύψος = 5 και ζητάμε το εμβαδό του. Θα έπρεπε να είναι 4 x 5 = 20, αλλά λαμβάνουμε 25.

Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ 28

Αρχή της Υποκατάστασης της Liskov

(5/6) class Rectangle {

protected int m_width; protected int m_height;

public void setWidth(int width)

{m_width = width;}

public void setHeight(int height)

{m_height = height;}

public int getWidth()

{return m_width;}

public int getHeight()

{return m_height;}

public int getArea()

{return m_width * m_height;}} Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ 29

Αρχή της Υποκατάστασης της Liskov

(6/6) class Square extends Rectangle { public void setWidth(int width){

m_width = width; m_height = width;}

public void setHeight(int height){

m_width = height; m_height = height; }

class LspTest

{ }

private static Rectangle getNewRectangle()

{

// antikeimeno apo kapoio factory ...

return new Square();

}

public static void main(String args[])

{ Rectangle r = LspTest.getNewRectangle(); r.setWidth(4); r.setHeight(5); System.out.println(r.getArea()); }} Το αποτέλεσμα θα είναι 25, αντί 20.

Δεν είναι τελικά ένα τετράγωνο επίσης και ένα ορθογώνιο ;;;;;

Όσον αφορά τη συμπεριφορά ΌΧΙ. Η αρχή LSP επιβάλει ότι σε μία σχέση κληρονομικότητας η

συμπεριφορά των παράγωγων κλάσεων

πρέπει να μπορεί να υποκαταστήσει τη συμπεριφορά των βασικών κλάσεων.

Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ 30

Αρχή της Αντιστροφής των Εξαρτήσεων

(1/6)

Αρχή Αντιστροφής των Εξαρτήσεων (DIP):

α. Οι μονάδες υψηλού επιπέδου δεν θα πρέπει να εξαρτώνται από μονάδες

χαμηλού επιπέδου.

β. Οι αφαιρέσεις δεν θα πρέπει να εξαρτώνται από λεπτομέρειες. Οι λεπτομέρειες

θα πρέπει να εξαρτώνται από αφαιρέσεις.

 Στη Δομημένη Ανάλυση και Σχεδίαση (SADT) δημιουργούνται δομές όπου οι υψηλότερες μονάδες στην ιεραρχία καλούν μονάδες χαμηλότερων επιπέδων (άρα εξαρτώνται από αυτές). Η γενική στρατηγική του συστήματος εξαρτάται από τις λεπτομέρειες υλοποίησης των μονάδων χαμηλού επιπέδου.  Μία τέτοια δομή δεν είναι λογικά σωστή. Οι μονάδες στα υψηλότερα επίπεδα εμπεριέχουν τους γενικούς κανόνες της εφαρμογής και του πεδίου του προβλήματος (business rules) και συνεπώς πρέπει να έχουν προτεραιότητα και να είναι ανεξάρτητες από τις λεπτομέρειες υλοποίησης. Δυσκολία στην επαναχρησιμοποίηση. Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ 31

Αρχή της Αντιστροφής των Εξαρτήσεων

(2/6)

Στόχος της αρχής της Αντιστροφής των Εξαρτήσεων

(Dependency-Inversion Principle)

είναι να

αντιστρέφει πλήρως τη δομή

ενός συστήματος λογισμικού, έτσι ώστε οι μονάδες υψηλού επιπέδου να μην εξαρτώνται αλλά να

καθορίζουν

τους κανόνες για τις μονάδες χαμηλού επιπέδου.

Αντεστραμμένη Διαστρωμάτωση:

Η αφηρημένη διασύνδεση στο ανώτερο στρώμα και η υλοποιούσα στο χαμηλό στρώμα. Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ 32

Αρχή της Αντιστροφής των Εξαρτήσεων

(3/6) Γενικός κανόνας: Να μην εξαρτόμαστε από συγκεκριμένες κλάσεις, αλλά από αφηρημένες διασυνδέσεις.

Όλες οι σχέσεις σε ένα πρόγραμμα θα πρέπει να καταλήγουν σε μία αφηρημένη κλάση ή σε μία διασύνδεση.

Σύμφωνα με αυτόν τον κανόνα:  Καμία μεταβλητή δεν θα πρέπει να διατηρεί έναν δείκτη ή μία αναφορά προς κάποια συγκεκριμένη κλάση  Καμία κλάση δεν θα πρέπει να κληρονομεί μία συγκεκριμένη κλάση   Καμία μέθοδος δεν θα πρέπει να επικαλύπτει υλοποιημένη μέθοδο οποιασδήποτε από τις γονικές της κλάσεις Οι ανωτέρω κανόνες θα παραβιαστούν τουλάχιστον μία φορά, στο σημείο που κατασκευάζουμε στιγμιότυπα  Επιπλέον, δεν υπάρχει λόγος να τους ακολουθήσουμε αν γνωρίζουμε ότι μία συγκεκριμένη κλάση δεν θα αλλάξει Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ 33

Αρχή της Αντιστροφής των Εξαρτήσεων

(4/6) Παράδειγμα

Ένας ελεγκτής (Controller) αντιλαμβάνεται κάποια αλλαγή στο εξωτερικό περιβάλλον και αποστέλλει μήνυμα ενεργοποίησης/απενεργοποίησης στο σχετιζόμενο αντικείμενο συναγερμού (LampAlarm).

LampAlarm Controller

+turnOn() +turnOff() • Η κλάση Controller ελέγχει αντικείμενα VisibleAlarm και μόνον αυτά • Αν αλλάξει ο πηγαίος κώδικας της LampAlarm (π.χ. πράσινο φως) θα πρέπει να επαναμεταγλωττιστεί και ο κώδικας της Controller • Αν θέλουμε να συνδέσουμε τον ελεγκτή με άλλο μηχανισμό (π.χ. έναν κινητήρα), πρέπει να τροποποιήσουμε τον ελεγκτή • Η πολιτική

υψηλού επιπέδου δεν έχει διαχωριστεί από την υλοποίηση

Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ 34

Αρχή της Αντιστροφής των Εξαρτήσεων

(5/6) Εντοπισμός της Υποκείμενης Αφαίρεσης και Αντιστροφή της Εξάρτησης: Controller

«interface»

ControllerServer

+turnOn() +turnOff()

LampAlarm Ευελιξία:

Τα αντικείμενα Controller ελέγχουν οτιδήποτε συμμορφώνεται με τη διασύνδεση ControllerServer. Ακόμα τα αντικείμενα που θα δημιουργηθούν στο μέλλον (επέκταση). Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ 35

Αρχή της Αντιστροφής των Εξαρτήσεων

(6/6) Συμπερασματικά:

Διαδικασιακός προγραμματισμός:

Δομές όπου οι μονάδες υψηλού επιπέδου εξαρτώνται από τις μονάδες χαμηλού επιπέδου.

• Ατυχής Επιλογή: Η πολιτική του συστήματος είναι ευάλωτη σε αλλαγές της υλοποίησης.

Αντικειμενοστρεφής Προγραμματισμός: Δομές αντεστραμμένες

• Πολλοί θεωρούν τη διαφορά αυτή ως ειδοποιό.

Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ 36

Αρχή του Διαχωρισμού των Διασυνδέσεων

(1/5)

Αρχή Διαχωρισμού των Διασυνδέσεων (ISP)

1ος ορισμός:

Πολλές εξειδικευμένες διασυνδέσεις είναι προτιμότερες από μια γενική διασύνδεση

2ος ορισμός:

Οι πελάτες δεν θα πρέπει να εξαναγκάζονται σε εξάρτηση από μεθόδους που δεν χρησιμοποιούν.

Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ 37

Αρχή του Διαχωρισμού των Διασυνδέσεων

(2/5)  Θα πρέπει να εξετάζεται προσεκτικά η σχεδίαση των διασυνδέσεων  Η αρχή ISP διαπραγματεύεται τα μειονεκτήματα των ογκωδών διασυνδέσεων

("fat" interfaces).

 Οι κλάσεις που έχουν μεγάλο αριθμό δημόσιων μεθόδων είναι κλάσεις των οποίων η διασύνδεση

δεν είναι συνεκτική

και οι μέθοδοι μπορούν να διαχωριστούν σε ένα σύνολο διασυνδέσεων. Κάθε σύνολο εξυπηρετεί μία διαφορετική ομάδα από πελάτες.

 Οι πελάτες θα πρέπει να γνωρίζουν

πολλές αφηρημένες κλάσεις

βάσης με

συνεκτικές διασυνδέσεις.

Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ 38

Αρχή του Διαχωρισμού των Διασυνδέσεων

(3/5)

Παράδειγμα παραβίασης της αρχής (ISP):

Fat – διασύνδεση που αναγκάζει τις υλοποιούσες υποκλάσεις να εκτελούν μη χρήσιμες – μεθόδους.

public class Dog implements Animal { public interface Animal {

public void fly() { } void fly(); public void bark() {//kodikas} void run(); void bark();} public void run() {//kodikas}}

public class Bird implements Animal {

public void bark() { /* den xreiazetai */ } public void run() {// kodikas } public void fly() { // kodikas}}

public class Cat implements Animal {

public void fly() {/* den xreiazetai */ } public void bark() {/* den xreiazetai */ } public void run() {// kodikas}} Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ 39

Αρχή του Διαχωρισμού των Διασυνδέσεων

(4/5)

Παράδειγμα υλοποίησης σύμφωνα με την αρχή ISP: Πολλές εξειδικευμένες διασυνδέσεις.

public interface Flyable

{void fly();}

public interface Runnable

{void run();}

public interface Barkable

{void bark();}

public class Bird implements Flyable, Runnable

{

public void run()

{//kodikas}

public void fly()

{//kodikas}}

public class Cat implements Runnable

{

public void run()

{//kodikas}}

public class Dog implements Runnable, Barkable { public void bark()

{//kodikas}

public void run()

{//kodikas}} Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ 40

Αρχή του Διαχωρισμού των Διασυνδέσεων

(5/5)

Συμπερασματικά:

Σε μια καλή σχεδίαση, οι πελάτες θα πρέπει να εξαρτώνται μόνο από τις μεθόδους τις οποίες καλούν

Αυτό επιτυγχάνεται διαχωρίζοντας τη διασύνδεση σε πολλές διασυνδέσεις, μία για κάθε κατηγορία πελατών

Παναγιώτης Σφέτσος, Μεθοδολογίες Προγραμματισμού ΙΙ 41