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

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

Ευρετικοί Κανόνες Αντικειμενοστρεφούς Σχεδίασης Object-Oriented Design Heuristics Μεταπτυχιακό Πρόγραμμα Σπουδών, Τμ. Εφ. Πληροφορικής.

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


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

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

2 Ευρετικοί Κανόνες Πέρας της φάσης "Σχεδίαση Λογισμικού": "Πρόκειται για καλή σχεδίαση ή όχι ?" Συνήθως η απάντηση δίδεται από τους guru της ομάδας ! O Arthur J. Riel σε μία προσπάθεια να εξαλείψει την αναγκαιότητα τέτοιων εμπειρογνωμόνων, κατέγραψε 68 εμπειρικούς κανόνες. Οι κανόνες αυτοί δεν είναι αυστηρές προδιαγραφές που πρέπει να τηρούνται υποχρεωτικά. Πολλοί κανόνες έρχονται σε αντίθεση μεταξύ τους Όπως κάθε engineering activity υπόκειται σε συμβιβασμούς Πρόκειται για εμπειρικούς κανόνες -> Δυσκολία στην αυτοματοποίηση

3 Ευρετικοί Κανόνες Παραδείγματα τέτοιων κανόνων που έχουμε δει ήδη (ερμηνεύονται με βάση τις αρχές Σχεδίασης): Όλα τα δεδομένα θα πρέπει να βρίσκονται κρυμμένα στην κλάση τους Οι χρήστες μιας κλάσης θα πρέπει να εξαρτώνται από τη δημόσια διασύνδεσή της αλλά μία κλάση δεν θα πρέπει να εξαρτάται από τους χρήστες της Ελαχιστοποιείστε τον αριθμό των μηνυμάτων που μπορεί να δεχθεί μία κλάση Υλοποιείστε μία ελάχιστη δημόσια διασύνδεση την οποία υλοποιούν όλες οι κλάσεις (π.χ. λειτουργίες copy, έλεγχο ισότητας, printing κλπ) Μην γεμίζετε τη δημόσια διασύνδεση μιας κλάσης με στοιχεία τα οποία οι χρήστες της κλάσης δεν μπορούν ή δεν ενδιαφέρονται να χρησιμοποιήσουν Κάθε κλάση θα πρέπει να ενσωματώνει μία και μόνο μία κύρια αφαίρεση Συσχετιζόμενα δεδομένα και συμπεριφορά θα πρέπει να διατηρούνται στο ίδιο σημείο Να είστε σίγουροι ότι οι αφαιρέσεις που μοντελοποιείτε είναι κλάσεις και όχι ρόλοι που έχουν κάποια αντικείμενα

4 Ευρετικοί Κανόνες Σύγκριση δομών διαδικασιακών και αντικειμενοστρεφών συστημάτων Θεωρούμε μία εφαρμογή η οποία μπορεί να διασπασθεί σε πέντε συναρτήσεις.

5 Ευρετικοί Κανόνες Οι δομές δεδομένων δημιουργούνται ως δεύτερη σκέψη, κατά τη διάρκεια της υλοποίησης των συναρτήσεων. Τα μέλη της ομάδας ανάπτυξης αντιλαμβάνονται κατά την υλοποίηση ότι ορισμένες συναρτήσεις μπορούν να μοιράζονται τμήματα των υποκείμενων δεδομένων. Στον διαδικασιακό προγραμματισμό οι εξαρτήσεις των δεδομένων (δηλαδή τα δεδομένα από τα οποία εξαρτάται ένα τμήμα κώδικα) ανακαλύπτονται εξετάζοντας απλά την υλοποίηση των συναρτήσεων. (τυπικές παράμετροι, τοπικές μεταβλητές και προσπελαζόμενες καθολικές μεταβλητές). Είναι όμως προβληματικό το αντίθετο: Ο εντοπισμός των διαδικασιακών εξαρτήσεων ενός δεδομένου (δηλαδή οι συναρτήσεις οι οποίες εξαρτώνται από ένα δεδομένο). Στο διαδικασιακό προγραμματισμό δεν υπάρχει σαφής συσχέτιση μεταξύ δεδομένων και λειτουργικότητας.

6 Ευρετικοί Κανόνες Είναι πλέον πιθανό, να πραγματοποιηθούν όλες οι αλλαγές στα δεδομένα και στις συναρτήσεις f1() και f2() χωρίς όμως το πρόγραμμα τα λειτουργεί σωστά (αγνοώντας την f6() ) Το πρόβλημα έγκειται στη μη τεκμηριωμένη εξάρτηση δεδομένων/συμπεριφοράς λόγω της μονόδρομης συσχέτισης μεταξύ κώδικα και δεδομένων. Σχεδόν όλα τα συστήματος που βασίζονται σε διαδικασιακό τρόπο ανάπτυξης έχουν μία αλυσιδωτή δομή εξαρτήσεων (spaghetti-like code) όπου κάθε τμήμα κώδικα αποτελεί μέρος αυτής. Έστω ότι τροποποιείται η X τροποποιούνται f6() Αν όμως έχει δημιουργηθεί στο ενδιάμεσο μια συνάρτηση που εξαρτάται από το Χ;

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

8 Ευρετικοί Κανόνες Ωστόσο: η εικόνα σε ένα διαδικασιακό σύστημα δεν είναι πάντοτε τόσο κακή ούτε βέβαια η εικόνα ενός αντικειμενοστρεφούς συστήματος τόσο ρόδινη

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

10 Ευρετικοί Κανόνες Κακή εξέλιξη σε ένα αντικειμενοστρεφές σύστημα Τι μπορεί να "στραβώσει" σε ένα αντικειμενοστρεφές σχέδιο ώστε αυτό να μην εξελιχθεί καλά; Υπάρχουν δύο κύρια είδη τέτοιων προβλημάτων: Πρόβλημα "θεϊκής κλάσης" (God class) (μη ομοιόμορφη κατανομή της λειτουργικότητας του συστήματος) Πρόβλημα "πολλαπλασιασμού των κλάσεων" (proliferation of classes) ( δημιουργία υπερβολικού αριθμού κλάσεων) Το πρόβλημα των θεϊκών κλάσεων εμφανίζεται σε δύο μορφές, τη μορφή συμπεριφοράς και τη μορφή δεδομένων.

11 Ευρετικοί Κανόνες Το πρόβλημα της θεϊκής κλάσης - Μορφή Συμπεριφοράς Συνηθισμένο σφάλμα προγραμματιστών διαδικασιακού τρόπου ανάπτυξης κατά τη μετάβαση στο αντικειμενοστρεφές μοντέλο: Οι προγραμματιστές αυτοί προσπαθούν να δημιουργήσουν τον κεντρικό μηχανισμό ελέγχου που υπάρχει σε ένα διαδικασιακό σύστημα. Το αποτέλεσμα είναι μία υπερβολικά ανεπτυγμένη κλάση που αναλαμβάνει τις περισσότερες αρμοδιότητες, αφήνοντας μικρό μέρος λεπτομερειακών εργασιών στις υπόλοιπες στοιχειώδεις κλάσεις. Ένας αριθμός ευρετικών κανόνων μπορούν να βοηθήσουν για την αποφυγή δημιουργίας τέτοιων κλάσεων:

12 Ευρετικοί Κανόνες Ευρετικός Κανόνας 1 Η λειτουργικότητα του συστήματος θα πρέπει να κατανέμεται οριζοντίως όσο το δυνατόν πιο ομοιόμορφα, δηλαδή, οι κλάσεις υψηλού επιπέδου σε ένα σχέδιο θα πρέπει να μοιράζονται ομοιόμορφα την εργασία που πρέπει να πραγματοποιηθεί. Ευρετικός Κανόνας 2 Μή δημιουργείτε θεϊκές κλάσεις/αντικείμενα στο σύστημά σας. Να είστε ιδιαίτερα καχύποπτοι για κλάσεις των οποίων το όνομα περιλαμβάνει τους όρους Driver, Manager, System, Subsystem ή παρόμοιες έννοιες. Ευρετικός Κανόνας 3 Να είστε ιδιαίτερα προσεκτικοί με τις κλάσεις οι οποίες έχουν πολλές μεθόδους πρόσβασης στη δημόσια διασύνδεσή τους. Η ύπαρξη πολλών υποδηλώνει ότι συσχετιζόμενα δεδομένα και συμπεριφορά δεν διατηρούνται μαζί σε ένα σημείο. Ευρετικός Κανόνας 4 Να είστε ιδιαίτερα προσεκτικοί με τις κλάσεις που εμφανίζουν πολλή συμπεριφορά η οποία δεν σχετίζεται με επικοινωνία με άλλα αντικείμενα (noncommunicating behavior) δηλαδή μεθόδους οι οποίες δρουν σε ένα συγκεκριμένο υποσύνολο των μελών δεδομένων της κλάσης. Οι θεϊκές κλάσεις παρουσιάζουν συχνά πολλή συμπεριφορά τέτοιου τύπου.

13 Ευρετικοί Κανόνες Η ύπαρξη θεϊκών κλάσεων σε ένα σύστημα, συνεπάγεται την εμφάνιση πολλών μεθόδων get() και set() στις υπόλοιπες κλάσεις. Η αναγκαιότητα τέτοιων μεθόδων οφείλεται σε δύο λόγους: Είτε η κλάση που χρησιμοποιεί τις gets() και sets() υλοποιεί μία στρατηγική (policy) μεταξύ δύο ή περισσοτέρων κλάσεων είτε βρίσκεται στα όρια μεταξύ ενός αντικειμενοστρεφούς μοντέλου και της γραφικής διασύνδεσης χρήστη

14 Ευρετικοί Κανόνες Παράδειγμα: μοντέλο ενός ακαδημαϊκού συστήματος όπου υπάρχουν μαθήματα (courses), προσφερόμενες τάξεις (course offerings) και φοιτητές (student). Τα μαθήματα περιλαμβάνουν στατική πληροφορία (περιγραφή, αριθμός διδακτικών μονάδων, προαπαιτούμενα), οι προσφερόμενες τάξεις διατηρούν στατική και δυναμική πληροφορία (το προσφερόμενο μάθημα, αίθουσα, ώρες διδασκαλίας, λίστα ατόμων που παρακολουθούν), ενώ η κλάση φοιτητής περιέχει πληροφορία που αφορά τους φοιτητές (ονοματεπώνυμο, αριθμός μητρώου, λίστα μαθημάτων που έχει περάσει επιτυχώς κλπ).

15 Ευρετικοί Κανόνες Μία λειτουργία της "Προσφερόμενης Τάξης" αφορά την προσθήκη ενός φοιτητή. Πριν από την προσθήκη, η κλάση θα πρέπει να ελέγξει ότι ο συγκεκριμένος φοιτητής που της δίνεται έχει περάσει τα προαπαιτούμενα. Πώς γίνεται αυτός ο έλεγχος; Από τη μία ο φοιτητής γνωρίζει ποιά μαθήματα έχει περάσει αλλά από την άλλη το κάθε μάθημα γνωρίζει τα προαπαιτούμενά του. Κατ' ελάχιστον, απαιτείται η λήψη της πληροφορίας από τη μία κλάση και η μεταβίβασή της στην άλλη. Οι δύο εναλλακτικές φαίνονται στο σχήμα. Σε κάθε σχεδίαση απαιτείται η ύπαρξη μιας μεθόδου πρόσβασης get().

16 Ευρετικοί Κανόνες Jacobson's Objectory method: και στις δύο περιπτώσεις παραβιάζεται ένας κανόνας "η στρατηγική δεν θα πρέπει να τοποθετείται μέσα σε κλάσεις του προβλήματος οι οποίες εμπλέκονται στη λήψη της απόφασης". Υποστηρίζεται, ότι οι κλάσεις του πεδίου αχρηστεύονται γιατί συνδέονται με το πεδίο του προβλήματος που θέτει τη στρατηγική. Σύμφωνα με τη μεθοδολογία, η λύση συνίσταται: είτε στο να λάβει η κλάση CourseOffering και τη λίστα των προαπαιτούμενων και τη λίστα των μαθημάτων που έχουν εξεταστεί επιτυχώς και να αποφασίσει η ίδια, είτε να δημιουργηθεί μία ξεχωριστή κλάση ΈλεγκτηςΠροαπαιτουμένων για την εκτέλεση αυτής της λειτουργίας

17 Ευρετικοί Κανόνες Η τελευταία κλάση είναι μία ειδική περίπτωση κλάσης Ελεγκτή (Controller clas) που περιέχει μόνο συμπεριφορά. Παρόλο μία κλάση ελεγκτής καθιστά τις υπόλοιπες κλάσεις περισσότερο επαναχρησιμοποιήσιμες, μία τέτοια κλάση δεν έχει λόγο ύπαρξης. Τι θα έκαναν σε μία τέτοια περίπτωση οι κλάσεις Φοιτητής και Μάθημα; Σε μία τέτοια σχεδίαση, η κλάση ελεγκτής πραγματοποιεί τα πάντα ενώ οι υπόλοιπες περιλαμβάνουν μόνο συναρτήσεις get() και set(). Στην ουσία καταργείται το αντικειμενοστρεφές μοντέλο διαχωρίζοντας δεδομένα και συμπεριφορά.

18 Ευρετικοί Κανόνες Υπάρχει μία περίπτωση όπου είναι αναγκαία η ύπαρξη μεθόδων πρόσβασης και αναφέρεται σε αρχιτεκτονικές όπου ένα αντικειμενοστρεφές μοντέλο αλληλεπιδρά με τη γραφική διασύνδεση χρήστη. Ο ευρετικός κανόνας εδώ είναι ότι το μοντέλο θα πρέπει να είναι ανεξάρτητο από τη γραφική διασύνδεση, παρόλο που η τελευταία θα πρέπει να επιτρέπει την παρακολούθηση και τροποποίηση ορισμένων από τα δεδομένα του μοντέλου. Σε μία τέτοια αρχιτεκτονική, η γραφική διασύνδεση χρειάζεται την ύπαρξη μεθόδων get() και set() στις κλάσεις του μοντέλου. Σε τέτοια συστήματα οι κλάσεις του μοντέλου σπανίως έχουν ενδιαφέρουσα συμπεριφορά. Σε συστήματα διαχείρισης δεδομένων για παράδειγμα, οι κλάσεις επικοινωνούν με ένα DBMS, ανακτούν εγγραφές, τις προωθούν, τις τροποποιούν και επανεγγράφουν στη βάση. Ευρετικός Κανόνας 5 Σε εφαρμογές που αποτελούνται από ένα αντικειμενοστρεφές μοντέλο που αλληλεπιδρά με διασύνδεση χρήστη, το μοντέλο θα πρέπει να είναι ανεξάρτητο από τη διασύνδεση. Η διασύνδεση θα πρέπει να εξαρτάται από το μοντέλο.

19 Ευρετικοί Κανόνες Πρόβλημα της θεϊκής κλάσης - Μορφή Δεδομένων Το πρόβλημα της περίπτωσης αυτής εμφανίζεται συχνά κατά τη μετατροπή ενός υπάρχοντος συστήματος λογισμικού (legacy system) σε μία νέα αντικειμενοστρεφή σχεδίαση. Υπάρχον σύστημα επεξεργασίας κλήσεων

20 Ευρετικοί Κανόνες Κατά τη μετατροπή του συστήματος η ομάδα ανάπτυξης αποφασίζει να ενσωματώσει τη δομή δεδομένων σε μία κλάση, προσθέτοντας σε αυτή μεθόδους get() και set() για όλα τα μέλη δεδομένων. Οι συναρτήσεις επεξεργασίας μετατρέπονται σε κλάσεις - ελεγκτές οι οποίες χρησιμοποιούν τις μεθόδους πρόσβασης και τροποποίησης της κλάσης των δεδομένων. Το νέο σύστημα υπερτερεί από το αρχικό. Ωστόσο, η σχεδίασή του δεν είναι καλής ποιότητας. Η κλάση CallProcessingBlock είναι μία θεϊκή κλάση που διατηρεί όλα τα δεδομένα, ενώ οι κλάσεις-ελεγκτές παραβιάζουν την αρχή της ενσωμάτωσης (συγκέντρωσης δεδομένων και μεθόδων στο ίδιο σημείο).

21 Ευρετικοί Κανόνες Αντικειμενοστρεφές σύστημα χαμηλής ποιότητας

22 Ευρετικοί Κανόνες Η προηγούμενη αντιμετώπιση είναι η ευκολότερη λύση. Ορθή σχεδίαση: διαχωρισμός της κλάσης που διατηρεί τα δεδομένα σε τμήματα, βάσει των συναρτήσεων επεξεργασίας.

23 Ευρετικοί Κανόνες Πρόβλημα Πολλαπλασιασμού των Κλάσεων (Proliferation of Classes) 3 ευρετικοί κανόνες των οποίων η παραβίαση οδηγεί στο ανωτέρω πρόβλημα Διαγράψτε τις άσχετες κλάσεις από τη σχεδίαση Μία άσχετη κλάση είναι αυτή που η συμπεριφορά της δεν έχει κανένα νόημα για το πεδίο του προβλήματος. Συνήθως πρόκειται για κλάσεις που δεν έχουν άλλες λειτουργίες εκτός από set, get και print. Κατά τη διαγραφή τέτοιων κλάσεων δεν απομακρύνεται και η πληροφορία (μέλη δεδομένων) που διατηρούν, αλλά ενσωματώνεται ως ιδιότητα σε άλλες κλάσεις.

24 Ευρετικοί Κανόνες Διαγράψτε κλάσεις που βρίσκονται εκτός συστήματος Κλασσικό παράδειγμα μία αφαίρεση η οποία αποστέλλει μηνύματα προς το σύστημα αλλά δεν λαμβάνει κανένα μήνυμα από οποιαδήποτε κλάση. Παράδειγμα αισθητήρων: φυσικές διατάξεις ή συσκευές που παρέχουν πληροφορία χρήσιμη για το σύστημα. Ωστόσο δεν ενδιαφέρουν συνήθως οι μέθοδοι συλλογής, επεξεργασίας και καταγραφής των δεδομένων (πρόκειται για λειτουργίες στο επίπεδο του hardware) και κατά συνέπεια δεν υπάρχει λόγος μοντελοποίησής τους ως μέθοδοι κλάσεων. Παράδειγμα ATM. Το ερώτημα που τίθεται είναι συνήθως "Ο πελάτης του συστήματος είναι κλάση αφού στέλνει μηνύματα προς το ATM;". Ωστόσο μόνο η αποστολή μηνυμάτων δεν συνιστά συμπεριφορά στο πεδίο του προβλήματος. Ο πελάτης δεν λαμβάνει κανένα μήνυμα το οποίο να ενεργοποιεί λειτουργίες.

25 Ευρετικοί Κανόνες Μην μετατρέπετε λειτουργίες σε κλάσεις. Να είστε καχύποπτοι για κλάσεις των οποίων το όνομα είναι ένα ρήμα, ή παράγωγο ρήματος, ειδικά αυτές που παρουσιάζουν μόνο μία συμπεριφορά με νόημα (εξαιρούνται μέθοδοι set, get και print). Κλάσεις που εμφανίζονται σε μία σχεδίαση να έχουν μόνο μία ουσιαστική λειτουργία θα πρέπει να εξεταστούν με προσοχή. Οι λειτουργίες αυτές (μαζί με τυχόν δεδομένα που χρησιμοποιούν) ενδεχομένως να μπορούν να ενσωματωθούν σε κάποια κλάση που απομένει να εντοπιστεί.

26 Ευρετικοί Κανόνες Κλάσεις - Διαμεσολαβητές (Meiler Page-Jones - OOPSLA'87): "Σε μία αντικειμενοστρεφή φάρμα υπάρχει μία αντικειμενοστρεφής αγελάδα με αντικειμενοστρεφές γάλα. Θα πρέπει η αντικειμενοστρεφής αγελάδα να στείλει στο αντικειμενοστρεφές γάλα το μήνυμα "παρήγαγε τον εαυτό σου" ή θα πρέπει το αντικειμενοστρεφές γάλα να στείλει το μήνυμα στην αντικειμενοστρεφή αγελάδα "άρμεξε τον εαυτό σου"; Παρόλο που το παράδειγμα μπορεί να φαίνεται αστείο, εμφανίζεται διαρκώς, όπως για παράδειγμα στο μοντέλο μιας βιβλιοθήκης: Δεν είναι εύκολο να αποφασίσει κανείς αν ένα βιβλίο αποστέλλει μήνυμα "αρχειοθέτησης του" στη βιβλιοθήκη, ή εάν το μήνυμα αποστέλλεται από τη βιβλιοθήκη στο βιβλίο. Το πρόβλημα και στις δύο περιπτώσεις είναι κοινό. Υπάρχει ένα κοινό στοιχείο - κλειδί το οποίο λείπει. Στο πρώτο παράδειγμα είναι ένας αγρότης και στο δεύτερο ένας βιβλιοθηκονόμος. Είναι οι αφαιρέσεις αυτές κλάσεις;

27 Ευρετικοί Κανόνες Κατά τη διάρκεια της ανάλυσης, τέτοιες κλάσεις-διαμεσολαβητές μοντελοποιούνται καθώς αποτελούν μέρος του πραγματικού κόσμου. Ωστόσο, κατά τη διάρκεια της σχεδίασης, λαμβάνοντας υπόψη και τους διάφορους ευρετικούς κανόνες, το μοντέλο του πραγματικού κόσμου τροποποιείται. Τίθεται για παράδειγμα το ερώτημα "ποιά η χρήση ενός βιβλιοθηκονόμου στο σύστημα"; Αν πρόκειται μόνο για μία κλάση η οποία λαμβάνει μηνύματα και τα ξαναστέλνει, τότε γιατί να μην διαγραφεί από τη σχεδίαση μειώνοντας τον αριθμό των κλάσεων και συσχετίσεων;

28 Ευρετικοί Κανόνες Κλάσεις - διαμεσολαβητές εντοπίζονται συχνά κατά τη διάρκεια της ανάλυσης μιας εφαρμογής. Κατά τη σχεδίαση, πολλοί διαμεσολαβητές αποδεικνύονται άσχετοι και θα πρέπει να διαγράφονται από το μοντέλο. Αναφορικά με το ποιά κλάση πρέπει να αποστέλλει το μήνυμα, συνήθως σε λογικό επίπεδο δεν υπάρχει απάντηση, καθώς καμία λύση δεν μειονεκτεί έναντι της άλλης. Ορισμένες φορές σε επίπεδο φυσικής σχεδίασης υπάρχουν μικρά πλεονεκτήματα.

29 Ευρετικοί Κανόνες Ο ΝΟΜΟΣ ΤΗΣ ΔΗΜΗΤΡΑΣ - LAW OF DEMETER. O LoD προτάθηκε από τους Lieberherr και Holland το 1987. Κάθε μονάδα λογισμικού θα πρέπει να έχει περιορισμένη γνώση των υπολοίπων μονάδων. Θα πρέπει να γνωρίζει μόνο για τις μονάδες που σχετίζονται «στενά» με αυτήν Don’t talk to strangers. Talk only to your friends. Θεωρώντας ως μονάδα κάθε μέθοδο f μιας κλάσης C. H f πρέπει να καλεί μόνο άλλες μεθόδους της C μεθόδους κλάσεων που αποτελούν παραμέτρους της f μεθόδους κλάσεων των οποίων αντικείμενα δημιουργούνται στην f μεθόδους κλάσεων που αποτελούν επιστρεφόμενους τύπους μεθόδων της C μεθόδους κλάσεων που είναι μέλη δεδομένων της C

30 Ευρετικοί Κανόνες Παράδειγμα “The Paperboy, the Wallet and the Law of Demeter” Θεωρούμε ένα υποθετικό παιδί που κάνει διανομή εφημερίδων και το οποίο πληρώνεται από κάθε πελάτη στον οποίο παραδίδει μια εφημερίδα.

31 public class Customer { private String firstName; private String lastName; private Wallet myWallet; public Customer(String first, String last) { firstName = first; lastName = last; myWallet = new Wallet(); myWallet.addMoney(100); } public String getFirstName() { return firstName; } public String getLastName() { return lastName; } public Wallet getWallet() { return myWallet; }

32 public class Wallet { private float value; public Wallet() { value = 0; } public float getTotalMoney() { return value; } public void addMoney(float amount) { value += amount; } public void subtractMoney(float amount) { value -= amount; } Ένα πιο σύνθετο πορτοφόλι θα μπορούσε να περιέχει μια δομή δεδομένων με αναφορές προς πιστωτικές κάρτες, δίπλωμα οδήγησης, κάρτες μέλους σε συλλόγους κλπ.

33 public class PaperBoy { private String name; private float payment = 2; public PaperBoy(String text) { name = text; } public void sellPaper(Customer theCustomer) { Wallet customersWallet = theCustomer.getWallet(); if (customersWallet.getTotalMoney() > payment) customersWallet.subtractMoney(payment); else System.out.println("You cannot buy the paper!"); } public static void main(String[] args) { Customer C1 = new Customer( "Robert", "Jones"); PaperBoy P1 = new PaperBoy("Bob"); P1.sellPaper(C1); System.out.println("One paper sold. Paperboy now has 2 more Euros"); }

34 Ευρετικοί Κανόνες Η υλοποίηση της μεθόδου sellPaper() στην κλάση PaperBoy ισοδυναμεί με το να πάρει το παιδί για τις εφημερίδες το πορτοφόλι του πελάτη (!!), να ελέγξει για τη διαθεσιμότητα του απαραίτητου ποσού πληρωμής, και να εισπράξει μόνο του το ποσό χρεώνοντας το πορτοφόλι του πελάτη. Ποιο είναι το πρόβλημα στην ανωτέρω σχεδίαση; Προφανώς, στην πραγματικότητα, ένας συνετός άνθρωπος δεν θα έδινε το πορτοφόλι του, εμπιστευόμενος το παιδί ότι θα λάβει μόνο αυτά που πρέπει να εισπράξει. Στην περίπτωση ενός πιο σύνθετου πορτοφολιού, το παιδί για τις εφημερίδες θα είχε πρόσβαση και στις πιστωτικές κάρτες, διπλώματα κλπ. Με άλλα λόγια, στο αντικείμενο PaperBoy αποκαλύπτεται πολύ περισσότερη πληροφορία από ότι χρειάζεται.

35 Ευρετικοί Κανόνες Υπό όρους αντικειμενοστρεφούς σχεδίασης, αυτό σημαίνει ότι η κλάση PaperBoy "γνωρίζει" ότι ένας πελάτης έχει ένα πορτοφόλι και μπορεί να το διαχειριστεί. Όταν μεταγλωττίζεται η PaperBoy απαιτείται η ύπαρξη της Customer αλλά και της Wallet. Οι τρεις αυτές κλάσεις έχουν πλέον ισχυρή σύζευξη. Αν τροποποιηθεί η Wallet τότε θα πρέπει να τροποποιηθεί και η κλάση Customer (που είναι φυσικό) αλλά και η κλάση PaperBoy.

36 Ευρετικοί Κανόνες Eνα ακόμη κλασσικό πρόβλημα: Έστω ότι ο πελάτης υπέστη μια απώλεια του πορτοφολιού του (λόγω κλοπής !). Κάποιος σε μια ομάδα ανάπτυξης λογισμικού αποφάσισε ότι ένας καλός τρόπος μοντελοποίησης αυτής της κατάστασης είναι να θέσει την τιμή της αναφοράς myWallet σε null, προσθέτοντας μία μέθοδο της μορφής: public void setWallet(Wallet theWallet) { myWallet = theWallet; } C1.setWallet(null); //π.χ. στη main

37 Ευρετικοί Κανόνες Ωστόσο, θα δημιουργηθεί εξαίρεση κατά την εκτέλεση στη sellPaper() θα κληθεί μέθοδος μέσω μηδενικής αναφοράς Η αποφυγή του προβλήματος θα ισοδυναμούσε με «Αν ο πελάτης έχει πορτοφόλι, έλεγξε το ποσό που έχει μέσα, αν επαρκεί, πάρε τα χρήματα» !!! Γιατί δημιουργήθηκαν τα προβλήματα ??

38 public class PaperBoy { private String name; private float payment = 2; public PaperBoy(String text) { name = text; } public void sellPaper(Customer theCustomer) { Wallet customersWallet = theCustomer.getWallet(); if (customersWallet.getTotalMoney() > payment) customersWallet.subtractMoney(payment); else System.out.println("You cannot buy the paper!"); } public static void main(String[] args) { Customer C1 = new Customer( "Robert", "Jones"); PaperBoy P1 = new PaperBoy("Bob"); P1.sellPaper(C1); System.out.println("One paper sold. Paperboy now has 2 more Euros"); } Παραβίαση LoD (οι μέθοδοι δεν είναι): - μέθοδοι της κλάσης - μέθοδοι κλάσεων - παραμέτρων - μέθοδοι κλάσης αντικείμενο της οποίας δημιουργείται (με new) - μέθοδοι κλάσης που είναι επιστρεφόμενος τύπος - μέθοδοι κλάσης – μέλους δεδομένων

39 public class Customer {... public float getPayment(float amount) { if(myWallet != null) { if(myWallet.getTotalMoney() > amount) { myWallet.subtractMoney(amount); return amount; } return 0; } public class PaperBoy {... public void sellPaper(Customer theCustomer) { float moneyReceived = theCustomer.getPayment(payment); if (moneyReceived >= payment) System.out.println("Thank you very much!"); else System.out.println("You cannot buy the paper!"); }

40 Ευρετικοί Κανόνες Ο νόμος της Δήμητρας εφαρμόζεται σε: 1. Αλυσιδωτές προτάσεις εντολών get() value = object.getX().getY().getTheValue(); 2. Πλήθος προσωρινών αντικειμένων X tempX = object.getX(); Y tempY = X.getY(); Value value = Y.getTheValue();

41 Ευρετικοί Κανόνες ΚΛΗΡΟΝΟΜΙΚΟΤΗΤΑ – Γενίκευση – Εξειδίκευση Θεμελιώδης μηχανισμός στην ανάλυση και σχεδίαση συστημάτων χρησιμοποιείται: α) για να εκφραστούν τα κοινά στοιχεία (συμπεριφορά και ιδιότητες) μεταξύ δύο ή περισσοτέρων κλάσεων, περίπτωση στην οποία αναφερόμαστε και ως γενίκευση, β) για να προσδιοριστεί ότι μία κλάση αποτελεί ειδικότερη κατηγορία μιας άλλης κλάσης, περίπτωση στην οποία αναφερόμαστε και ως εξειδίκευση. Δεν είναι το ίδιο ?

42 Ευρετικοί Κανόνες Γενικεύσεις εντοπίζονται συνήθως στην πρώτη έκδοση ενός συστήματος: Τα μέλη της ομάδας ανάπτυξης ανακαλύπτουν κατά τη σχεδίαση ότι ορισμένες κλάσεις έχουν κοινή διασύνδεση ή κοινά δεδομένα. Αυτή η κοινή πληροφορία ενσωματώνεται σε μία γενικότερη υπερκλάση. Σχέσεις εξειδίκευσης εντοπίζονται κατά την ανάπτυξη μεταγενέστερων εκδόσεων Καθώς το λογισμικό εξελίσσεται για να συμπεριλάβει επιπρόσθετη λειτουργικότητα, ορισμένες λειτουργίες/δεδομένα απαιτούν ειδικό χειρισμό που δεν μπορεί να ενταχθεί στις υπάρχουσες κλάσεις.

43 Ευρετικοί Κανόνες Σύνηθες πρόβλημα κατανόησης: σύγχυση μεταξύ κληρονομικότητας και περιεκτικότητας. Αν μία κλάση Β (ορολογία: παράγωγη κλάση, υποκλάση, απόγονος ή κλάση παιδί) κληρονομεί μία κλάση Α (ορολογία: βασική κλάση, υπερκλάση, πρόγονος ή γονική κλάση), αποκτά ένα αντίγραφο των δεδομένων της Α. Ωστόσο, αν η κληρονομικότητα σήμαινε μόνο την αντιγραφή των δεδομένων της βασικής κλάσης στην παράγωγη κλάση, αυτή η σχέση θα ήταν άχρηστη. Η σχέση της περιεκτικότητας έχει ακριβώς την ίδια σημασιολογία. Ωστόσο, με τη σχέση της περιεκτικότητας η περιέχουσα κλάση δεν αποκτά (αυτομάτως) τις λειτουργίες της περιεχόμενης κλάσης. Ειδοποιός διαφορά στην κληρονομικότητα: Η παράγωγη κλάση διατηρεί τη λειτουργικότητα της βασικής κλάσης

44 Ευρετικοί Κανόνες Η κληρονομικότητα θα πρέπει να χρησιμοποιείται μόνο για τη μοντελοποίηση μιας ιεραρχίας εξειδικεύσεων Περιεκτικότητα: σχεδίαση black-box Kληρονομικότητα: σχεδίαση white-box καθώς ο χρήστης της παράγωγης κλάσης, για να την χρησιμοποιήσει, πρέπει να γνωρίζει τα δεδομένα και τις λειτουργίες της βασικής κλάσης. Αν χρησιμοποιούμε κληρονομικότητα εκεί όπου θα μπορούσαμε να χρησιμοποιήσουμε περιεκτικότητα, αποκαλύπτουμε χωρίς λόγο λεπτομέρειες υλοποίησης στους χρήστες μιας κλάσης.

45 Ευρετικοί Κανόνες Στη διασύνδεση της κλάσης ΑΒ η μέθοδος C δεν είναι "ορατή" και κατά συνέπεια ο χρήστης δεν μπορεί να στείλει μήνυμα C στην ΑΒ, ούτε φυσικά να παρακάμψει τη λειτουργία Β για την επίτευξη του ίδιου σκοπού. Στη διασύνδεση της κλάσης ΑΒ η μέθοδος C είναι "ορατή" ("Άνοιγμα της σχεδίασης")

46 Ευρετικοί Κανόνες Θα πρέπει να προτιμάται η σύνθεση αντικειμένων έναντι της κληρονομικότητας κλάσεων. Πέραν της “αποκάλυψης” στους χρήστες πλεονάζουσας πληροφορίας: η κληρονομικότητα ορίζεται κατά τη μεταγλώττιση η κληρονομικότητα ορισμένες φορές αναιρεί την ενσωμάτωση Έστω η κλάση HashSet των βιβλιοθηκών της Java. Η κλάση διαθέτει μεθόδους: προσθήκης ενός αντικειμένου add(Object o) προσθήκης μιας συλλογής addAll(Collection c) το μέγεθος (size) αναφέρεται στο τρέχον πλήθος αντικειμένων

47 Ευρετικοί Κανόνες Έστω ότι επιθυμούμε την προσθήκη λειτουργικότητας ώστε να γνωρίζουμε το συνολικό αριθμό στοιχείων που προστέθηκαν (ανεξαρτήτως του αν διαγράφηκαν στη συνέχεια) Ενδεδειγμένη λύση: ?...................... Κληρονομικότητα

48 Ευρετικοί Κανόνες import java.util.*; public class ExtendedHashSet extends HashSet { private int totalCounter = 0;//μετρητής στοιχείων public boolean add(Object o) { totalCounter++; return super.add(o); } public boolean addAll(Collection c) { totalCounter = totalCounter + c.size(); return super.addAll(c); } public int getTotalCounter() { return totalCounter; }

49 Ευρετικοί Κανόνες public static void main(String[] args) { ExtendedHashSet eList = new ExtendedHashSet(); eList.add(5); eList.add(6); System.out.println("After two inserts, totalCounter = " + eList.getTotalCounter()); //Τι εκτυπώνεται ? ArrayList alpha = new ArrayList(); alpha.add(10); alpha.add(12); eList.addAll(alpha); System.out.println("After four inserts, totalCounter = " + eList.getTotalCounter()); //Τι εκτυπώνεται ? }

50 Ευρετικοί Κανόνες Στην κλάση HashSet της Java η μέθοδος addAll() είναι βασισμένη στην add() !! Οι σχεδιαστές της HashSet δεν έλαβαν κάποια απόφαση που δημιουργεί προβλήματα στους πελάτες της κλάσης. Το γεγονός ότι για τη σωστή υλοποίηση των παράγωγων κλάσεων απαιτείται η γνώση λεπτομερειών της βασικής κλάσης καταργεί την ενσωμάτωση Λύση: Ο ευρετικός κανόνας που προαναφέρθηκε: Προτιμήστε σύνθεση !!

51 Ευρετικοί Κανόνες public class CompositeHashSet extends HashSet { private HashSet containedHashSet; //σχέση περιεκτικότητας private int totalCounter = 0; public CompositeHashSet() { containedHashSet = new HashSet(); } public boolean add(Object o) { totalCounter++; return containedHashSet.add(o); } public boolean addAll(Collection c) { totalCounter = totalCounter + c.size(); return containedHashSet.addAll(c); } public int getTotalCounter() { return totalCounter; }

52 Ευρετικοί Κανόνες Οι παράγωγες κλάσεις πρέπει να έχουν γνώση των βασικών τους κλάσεων εξ'ορισμού, αλλά οι βασικές κλάσεις δεν θα πρέπει να γνωρίζουν οτιδήποτε για τις παράγωγες κλάσεις. Αν οι βασικές κλάσεις γνωρίζουν τις παράγωγές τους κλάσεις, τότε υπονοείται ότι κατά την προσθήκη μιας νέας παράγωγης κλάσης, ο κώδικας της βασικής κλάσης θα πρέπει να τροποποιηθεί. Αυτό αποτελεί παραβίαση της αρχής της αντιστροφής των εξαρτήσεων καθώς η αφαίρεση (βασική κλάση) θα εξαρτάται από την υλοποίηση (παράγωγες κλάσεις). Βάθος ιεραρχιών κληρονομικότητας Θεωρητικά, οι ιεραρχίες κληρονομικότητας πρέπει να έχουν μεγάλο βάθος - όσο μεγαλύτερο βάθος τόσο καλύτερα. Θεωρητικό κίνητρο: με την ύπαρξη μιας μεγάλης ταξινομίας αφαιρέσεων, μία νέα παράγωγη κλάση μπορεί να διασχίσει την ιεραρχία κληρονομώντας την πιο εκλεπτυσμένη αφαίρεση (Πετρελαιοκίνητο_Αυτοκίνητο_4x4)

53 Ευρετικοί Κανόνες Στην πράξη, οι ιεραρχίες κληρονομικότητας δεν θα πρέπει να έχουν μεγαλύτερο βάθος από ότι ένας μέσος άνθρωπος μπορεί να κρατήσει στη μνήμη βραχείας διάρκειας. Μία συνηθισμένη τιμή για αυτό το βάθος είναι έξι. Κακή εμπειρία από έργα λογισμικού με υπερβολικά μεγάλες τιμές (12 έως 17 επίπεδα). Επιπρόσθετα, ο σχεδιαστής του συστήματος θα πρέπει να είναι σε θέση να γνωρίζει για μία δεδομένη κλάση, το σύνολο των μεθόδων και ιδιοτήτων που κληρονομεί για να μπορεί να τη χρησιμοποιήσει κατάλληλα. Όλες οι αφηρημένες κλάσεις πρέπει να είναι βασικές κλάσεις Αν από μία κλάση δεν μπορούν να κατασκευαστούν στιγμιότυπα, τότε η κλάση αυτή θα πρέπει να κληρονομείται από κλάσεις που θα δημιουργούν αντικείμενα. Αν δεν ισχύει αυτό, τότε η λειτουργικότητα της αφηρημένης κλάσης δεν μπορεί να προσπελαστεί από πουθενά.

54 Ευρετικοί Κανόνες Όλες οι βασικές κλάσεις πρέπει να είναι αφηρημένες Άλλη διατύπωση: "Καμία κλάση δεν πρέπει να κληρονομεί από κάποια συγκεκριμένη κλάση" Παράδειγμα: Θεωρούμε ένα σύστημα ενός πανεπιστημίου όπου μοντελοποιούμε τις έννοιες ενός φοιτητή (Student) και ενός διδακτορικού φοιτητή (PhDStudent) Απολύτως φυσιολογικά, ένας διδακτορικός φοιτητής αποτελεί ειδική περίπτωση ενός φοιτητή και αποφασίζεται η μοντελοποίηση των δύο εννοιών με κληρονομικότητα

55 Ευρετικοί Κανόνες Νέα απαίτηση: ζητείται η προσθήκη σε κάθε φοιτητή μιας μεθόδου getCredits(). Μπορεί να προστεθεί η συγκεκριμένη λειτουργικότητα στην Student χωρίς να προστεθεί και στην PhDStudent, την οποία όμως δεν αφορά; Αυτό ακριβώς είναι το πρόβλημα συντηρησιμότητας που δημιουργείται όταν μία συγκεκριμένη κλάση κληρονομεί μία άλλη συγκεκριμένη κλάση. Το ανωτέρω (σημαντικό σε πολλές περιπτώσεις πρόβλημα) μπορεί να αποφευχθεί αν θεωρήσουμε ότι και οι δύο κλάσεις έχουν κάτι κοινό. Η κοινή πληροφορία ενσωματώνεται σε μία αφηρημένη βασική κλάση (AllStudents)

56 Ευρετικοί Κανόνες Επίλυση προβλήματος ιδιαίτερα επίπονη. Ενώ ο κώδικας της κλάσης Student θα έπρεπε ούτως ή άλλως να τροποποιηθεί (για την προσθήκη της νέας μεθόδου), πλέον θα πρέπει να τροποποιηθεί και ο κώδικας της κλάσης PhDStudent, να επαναμεταγλωττιστεί και να μεταγλωττιστούν και ελεγχθούν εκ νέου όλες οι μονάδες λογισμικού που χρησιμοποιούν την PhDStudent. Ακόμα και αν κάποιος αποφάσισε να μην αλλάξει τη σχεδίαση, εκφυλίζοντας απλά την υλοποίηση της μεθόδου getCredits() στην κλάση PhDStudent, θα έπρεπε να αλλάξει τον κώδικα της, χωρίς να ελπίζει ότι τέτοια προβλήματα δεν θα δημιουργηθούν και στο μέλλον.

57 Ευρετικοί Κανόνες Οι ευρετικοί κανόνες δεν ισχύουν απόλυτα Έστω ότι δεν υπήρχαν τέτοιες αλλαγές στις απαιτήσεις. Τότε η "βελτιωμένη σχεδίαση" θα οδηγούσε σε μία παράγωγη κλάση η οποία δεν θα είχε καμία διαφορά από τη βασική της κλάση - κατά συνέπεια θα ήταν κενή

58 Ευρετικοί Κανόνες Πολύ συχνά προκύπτει η αναγκαιότητα διάκρισης μεταξύ των διαφορετικών ρόλων που μπορεί να έχει μια οντότητα Παράδειγμα: ένας υπάλληλος που δραστηριοποιείται σε μια εταιρεία είτε ως εξωτερικός συνεργάτης είτε ως εσωτερικός εργαζόμενος Μοντελοποιούμε τους ρόλους ως κλάσεις ή απλά ως μια ιδιότητα? Η απάντηση εξαρτάται από το αν οι διαφορετικοί ρόλοι εμπεριέχουν την ίδια συμπεριφορά ή όχι

59 Ευρετικοί Κανόνες α) Ίδια συμπεριφορά: απλή μεταβλητή που αντιστοιχεί στους δύο ρόλους β) Διαφορετική συμπεριφορά (π.χ. διαφορετικός τρόπος υπολογισμού κρατήσεων): μοντελοποίηση μέσω υποκλάσεων

60 Ευρετικοί Κανόνες Ευρετικός Κανόνας Διαφορετικοί ρόλοι σε ένα σύστημα πρέπει να αναπαριστώνται με τη χρήση διαφορετικών κλάσεων, εάν και μόνο αν οι ρόλοι αυτοί συνεπάγονται διαφορετική συμπεριφορά Αν μοντελοποιήσουμε ρόλους με διαφορετική συμπεριφορά με τη χρήση ιδιοτήτων καταλήγουμε σε παραβίαση της Ανοικτής-Κλειστής Σχεδίασης

61 Ευρετικοί Κανόνες Ευρετικός Κανόνας Ανάλυση περιπτώσεων βάσει της τιμής μιας ιδιότητας πρέπει συνήθως να αποφεύγεται. Η κλάση που περιλαμβάνει τους ελέγχους θα πρέπει να αποσυντεθεί σε μια ιεραρχία κλάσεων, όπου κάθε τιμή της ιδιότητας αντιστοιχίζεται σε μία παράγωγη κλάση Τεχνική Αναδόμησης: Replace Conditional with Polymorphism

62 Ευρετικοί Κανόνες Έστω ότι επιχειρείται η μοντελοποίηση μιας στοίβας (δομή LIFO): Λειτουργία που συνίσταται στις μεθόδους push() και pop() Οι διαφορετικές καταστάσεις της στοίβας συνεπάγονται διαφορετική λειτουργικότητα, επομένως:

63 Ευρετικοί Κανόνες Ωστόσο, πώς μοντελοποιείται το γεγονός ότι ένα αντικείμενο της κλάσης Στοίβα μπορεί να αλλάξει κατάσταση ? κατά τη διάρκεια της εκτέλεσης του προγράμματος το αντικείμενο θα πρέπει να αλλάξει κλάση ! Το πρόβλημα εμφανίζεται λόγω της προσπάθειας αντικατάστασης της ανάλυσης περιπτώσεων βάσει της τιμής μιας ιδιότητας Μια τέτοια ιδιότητα (κατάσταση στοίβας) υλοποιεί τη δυναμική σημασιολογία ενός αντικειμένου Η προσπάθεια μοντελοποίησης της δυναμικής σημασιολογίας αξιοποιώντας το μηχανισμό της κληρονομικότητας (που αφορά στατικά χαρακτηριστικά), οδηγεί στην ανάγκη αλλαγής τύπου κατά την εκτέλεση.

64 Ευρετικοί Κανόνες Ευρετικός Κανόνας Δεν θα πρέπει να επιχειρείται η μοντελοποίηση της δυναμικής σημασιολογίας μιας κλάσης μέσω της κληρονομικότητας δηλαδή ? κάνουμε ρητή ανάλυση περιπτώσεων ?

65 Ευρετικοί Κανόνες

66 Καλύτερη Λύση? Εφαρμογή του προτύπου State


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

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


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