Κατέβασμα παρουσίασης
Η παρουσίαση φορτώνεται. Παρακαλείστε να περιμένετε
ΔημοσίευσεDeo Zeno Τροποποιήθηκε πριν 9 χρόνια
1
1 HMMY Τεχνολογία Λογισμικού Διδάσκων Κώστας Κοντογιάννης Αναπλ. Καθηγητής, Ε.Μ.Π
2
2 Ταξινόμηση Κοινών Σ.Μ - GoF Behavioural (Μοτίβα Συμπεριφοράς) Structural (Δομικά Μοτίβα) Creational (Μοτίβα Δημιουργίας) Visitor Iterator Observer State Template Method Chain of Responsibility Strategy Command Interpreter Mediator Memento Decorator Adapter Bridge Composite Facade Proxy Flyweight Abstract Factory Factory Method Singleton Builder Prototype
3
3 Σχεδιαστικό Μοτίβο Decorator (Structural) Σκοπός –Να προσθέσουμε νέες λειτουργίες στις μεθόδους κάποιου αντικειμένου Εφαρμογή –Όταν δεν είναι πρακτικά εφικτό να επεκτείνουμε τις λειτουργίες ενός αντικειμένου με τη χρήση κληρονομικότητας (υπο-κλάσεις) –Όταν θέλουμε να επεκτείνουμε δυναμικά τις λειτουργίες και να μπορούμε να τις αφαιρέσουμε εάν αυτό χρειάζεται
4
4 Decorator – Διάγραμμα Κλάσης
5
5 Decorator – Γενικά Το σχεδιαστικό μοτίβο Decorator είναι επίσης γνωστό με το όνομα Wrapper. Η δομή αυτού του μοτίβου βασίζεται στην χρήση ενός αντικειμένου (Decorator) που έχει την ίδια διαπροσωπία με το αντικείμενο για το οποίο θέλουμε να επεκτείνουμε τις λειτουργίες. Όταν καλούμε μια μέθοδο του Decorator, αυτή η κλήση προωθείται στο αντικείμενο που ο Decorator «περιβάλλει». Στη διαδρομή η μέθοδος του Decorator συμπληρώνει νέες λειτουργίες που καλούνται πριν ή μετά τη κλήση της αρχέτυπης μεθόδου του αντικειμένου που «περιβάλλεται». Η χρησιμότητα αυτού του Σχεδιαστικού Μοτίβου είναι ότι μπορούμε να επαυξάνουμε τις λειτουργίες συγκεκριμένων αντικειμένων αντί όλων των αντικειμένων που μπορούν να προκύψουν από μία κλάση. Με τη χρήση αυτού στου σχεδιαστικού μοτίβου μπορούμε να επαυξήσουμε τις λειτουργίες ενός και μόνο αντικειμένου, αφήνοντας όλα τα άλλα αντικείμενα της ίδιας κλάσης αμετάβλητα. Η χρήση υπο-κλάσεων χωρίς την εφαρμογή αυτού του σχεδιαστικού μοτίβου θα οδηγούσε στο πρόβλημα ότι δεν θα μπορούσαμε να αναβαθμίσουμε μόνο συγκεκριμένα αντικείμενα της κλάσης.
6
6 Decorator - Σχόλια Αυτό το Σχεδιαστικό Μοτίβο παρέχει αρκετή σχεδιαστική ευελιξία διότι μπορούμε να αλλάξουμε τη συμπεριφορά κάποιου Decorator κατά τη διάρκεια της λειτουργίας του προγράμματος και δεν χρειάζεται να συμβολομεταφράσουμε το πρόγραμμα εξ’ αρχής. Καθώς η κλάση του Decorator έχει την ίδια διαπροσωπεία με το αντικείμενο που «περιβάλλει», ένα αντικείμενο αυτού του τύπου Decorator παρουσιάζει στους πελάτες την ίδια εικόνα που θα παρουσίαζε ένα αντικείμενο κάποιου αντικειμένου που «περιβάλλεται» από τον Decorator. Είναι ενδιαφέρον να παρατηρήσουμε ότι μπορούμε να «περιβάλλουμε» ένα Decorator με άλλους Decorators και κάθε άλλο αντικείμενο του προγράμματος δεν θα έβλεπε κάποια διαφορά στη διαπροσωπία. Αυτό μας δίνει μεγάλες δυνατότητες προσαρμοστικότητας της λειτουργίας ακόμη και σε συγκεκριμένα αντικείμενα.
7
7 Decorator – Σχόλια Επακόλουθα +Λειτουργίες μπορούν να προστεθούν / αφαιρεθούν κατά τη διάρκεια της λειτουργίας του συστήματος +Αποφεύγεται η χρήση πολλαπλών υπο-κλάσεων +Αναδρομική χρήση και ενθυλάκωση επιτρέπει τη προσαρμογή της λειτουργίας όπως εμείς θέλουμε –Περιορισμοί στον ορισμό διαπροσωπιών –Κρίση ταυτότητας (τι κάνει τελικά ένα αντικείμενο?) Υλοποίηση –Πρέπει να υποστηρίζουμε την ίδια διαπροσωπία –Χρήση abstract base class για την αρχική κλάση Decorator –‘Οταν έχουμε μεγάλες base classes (με πολλές μεθόδους) ίσως η χρήση του μοτίβου Strategy να είναι πιο κατάλληλη
8
8 Decorator –Παράδειγμα
9
9 class Book extends LibItem{ String author; int noCopies; int onShelf; String title; public Book(String t, String a, int c){ title = t; noCopies= c; author = a; onShelf= c; } public String getTitle() { return title; } public int getCopies() { return noCopies; } public int copiesOnShelf() { return onShelf; } public void decCopiesOnShelf() { onShelf--; } public void incCopiesOnShelf() { onShelf++; } public String getAuthor() { return author; } public void borrowItem(String borrower) { System.out.println("borrow–in Book"); } public void returnItem(String borrower) { } public void reserve(String reserver) { } } /* End class Book */
10
10 Decorator - Παράδειγμα abstract class Decorator extends LibItem{ LibItem item; public Decorator(LibItem li) { item = li; } public String getTitle() { return item.getTitle(); } // Following methods are // similarly implemented public String getAuthor() {... public int getCopies() {... public int copiesOnShelf() {... public void decCopiesOnShelf() { item.decCopiesOnShelf(); } // and similarly... public void incCopiesOnShelf() {...
11
11 Decorator – Παράδειγμα
12
12 Decorator – Παράδειγμα Πελάτη // Non borrowable, non reservablebook LibItem b1 = new Book("A", "B", 1); // Borrowablevideo LibItem v1 = new BorrowableDec(new Video("V", 3)); // borrow unborrowableitem -copies should stay 1 b1.borrowItem("Bob"); System.out.println("Copiesof book = " +b1.copiesOnShelf()); // borrow video -copies decremented to 2 v1.borrowItem("Fred"); System.out.println("Copiesof video = " +v1.copiesOnShelf()); //make book borrowable and borrow it -copies = 0 LibItem b2 = new BorrowableDec(b1); b2.borrowItem("Bob"); System.out.println("Copiesof book = " +b2.copiesOnShelf()); // make book reservable LibItem b3 = new ReservableDec(b2); b3.reserve("Alice"); b3.returnItem("Bob"); // book returned -back to 1 copy System.out.println("Copiesof book = " +b3.copiesOnShelf()); // Not reserved for Jane -still 1 copy b3.borrowItem("Jane"); System.out.println("Copiesof book = " +b3.copiesOnShelf()); // Okay Alice can borrow -down to 0 b3.borrowItem("Alice"); System.out.println("Copiesof book = " +b3.copiesOnShelf());
13
13 Σχεδιαστικό Μοτίβο Adapter Το Σχεδιαστικό Μοτίβο Adapter παρέχει τη δυνατότητα σε κάποιο κώδικα πελάτη να χρησιμοποιήσει ένα αντικείμενο του οποίου η διαπροσωπία είναι διαφορετική από αυτή που περιμένει ο κώδικας πελάτης, χωρίς να χρειαστεί να αλλάξει ούτε ο κώδικας πελάτης ούτε το αντικείμενο που παρέχει την υπηρεσία Αυτό το μοτίβο είναι χρήσιμο σε καταστάσεις όταν: –1) Θέλουμε να αντικαταστήσουμε μια κλάση με κάποια άλλη και οι διαπροσωπίες τους διαφέρουν, χωρίς να χρειαστεί να αλλάξουμε τον κώδικα-πελάτη –2) Θέλουμε να υλοποιήσουμε μια κλάση που αλληλεπιδρά με άλλες κλάσεις για τις οποίες δεν γνωρίζουμε τις διαπροσωπίες τους κατα τη φάση της σχεδίασης του συστήματος
14
14 Δομικά Στοιχεία του Σχεδιαστικού Μοτίβου Adapter Συμμετέχουσες κλάσεις. Οι κλάσεις και τα αντικείμενα που δομούν το μοτίβο είναι: –Κλάση Target Είναι μια κλάση που ορίζει τη διαπροσωπία που περιμένει και χρησιμοποιεί ο κώδικας – πελάτης –Κλάση Adaptee Είναι μια κλάση που ορίζει τη διαπροσωπεία που τελικά χρησιμοποιείται –Κλάση Adapter Είναι η κλάση που προσαρμόζει τη διαπροσωπία της κλάσης Adaptee στη διαπροσωπία της κλάσης Target –Κλάση Client Είναι η κλάση που περιλαμβάνει κώδικα πελάτη που χρησιμοποιεί τη διαπροσωπία της κλάσης Target
15
15 Adapter – Λειτουργία / Κατασκευή Πρώτα σχεδιάζουμε και υλοποιούμε τη κλάση Target που ορίζει τις μεθόδους και διαπροσωπίες που περιμένει ο κώδικας – πελάτης Κατόπιν, σχεδιάζουμε και υλοποιούμε τη κλάση Adapter, που ορίζει και υλοποιεί τη διαπροσωπία που χρειάζεται, για να προσπελαστούν οι λειτουργίες (μέθοδοι) της κλάσης Adaptee. Η κλάση Adapter είναι υπο-κλάση της κλάσης Target, και παρέχει μια τροποποίηση των κλήσεων που έρχονται από τον κώδικα πελάτη σε μια μορφή που μπορεί να γίνει συμβατή για τη κλήση των κατάλληλων λειτουργιών της κλάσης Adaptee. Η κλάση Adapter υπερκαλύπτει (overrides) τις αντίστοιχες μεθόδους της κλάσης Target και τις υλοποιεί με τέτοιο τρόπο που να είναι συμβατές με τη διαπροσωπία που περιμένει η κλάση Adaptee. Αυτό το μοτίβο δίνει το πλεονέκτημα ότι ο κώδικας πελάτης δεν χρειάζεται να αλλάξει, παρότι οι κλάσεις που πραγματικά χρησιμοποιεί μπορούν να αλλάξουν. Αυτό είναι ιδιαίτερα χρήσιμο κατά τη σχεδίαση και υλοποίηση μεγάλων συστημάτων όπου οι διαπροσωπίες μερικών κλάσεων θα χρειαστεί να αλλαχθούν κατά τη διάρκεια της περιόδου σχεδίασης / υλοποίησης
16
16 Adapter – Διάγραμμα Κλάσης
17
17 Adapter - Παράδειγμα // "Target" class Target { public virtual void Request() { Console.WriteLine("Called Target Request()"); } } class Adapter : Target { private Adaptee adaptee = new Adaptee(); public override void Request() { // Possibly do some other work // and then call SpecificRequest adaptee.SpecificRequest(); } } // "Adaptee" class Adaptee { public void SpecificRequest() { Console.WriteLine("Called SpecificRequest()"); } } } // Client class MainApp { static void Main() { // Create adapter and place a request Target target = new Adapter(); target.Request(); // Wait for user Console.Read(); } } Output Called SpecificRequest()
18
18 Σχεδιαστικό Μοτίβο Bridge Αυτό το Σχεδιαστικό Μοτίβο χρησιμοποιείται για να μπορούμε να ξεχωρίζουμε ένα αφαιρετικό μοντέλο από την πιθανή υλοποίηση ή υλοποιήσεις του. Δηλαδή, να μπορούμε να έχουμε διάφορα αφαιρετικά μοντέλα (π.χ. ορισμούς διαφόρων πρωτοκόλλων) και διαφορετικές υλοποιήσεις αυτών των μοντέλων, και να επιλέγουμε μέσα από τον κώδικα κατά την εκτέλεση του προγράμματός μας ποια υλοποίηση θέλουμε να χρησιμοποιήσουμε Το Σχεδιαστικό Μοτίβο Bridge είναι ιδιαίτερα χρήσιμο όταν έχουμε μια ιεραρχική δόμηση των αφαιρετικών μοντέλων και παράλληλα έχουμε μια αντίστοιχη ιεραρχική δόμηση υλοποιήσεων αυτών των μοντέλων (π.χ. η TCP/IP δομή μοντέλων στα δίκτυα υπολογιστών και αντίστοιχες μια ή περισσότερες υλοποιήσεις αυτών των πρωτοκόλλων). Το σχεδιαστικό μοτίβο, επιτρέπει να επιλέξουμε την υλοποίηση που θέλουμε να χρησιμοποιήσουμε από το ίδιο μας τον κώδικα κατά την εκτέλεση του. Οι κλάσεις των αφαιρετικών μοντέλων και των υλοποιήσεων τους, μπορούν να υλοποιηθούν και να συνδυαστούν ανεξάρτητα. Αυτό το Σχεδιαστικό Μοτίβο μπορεί να χρησιμοποιηθεί για την υλοποίηση της Αρχιτεκτονικής Τεχνοτροπίας των Διαδοχικών Επιπέδων (Layered Architecture). Επίσης σχετίζεται με το Σχεδιαστικό Μοτίβο Abstract Factory, όπου το Μοτίβο Bridge, μπορεί να χρησιμοποιήσει το Μοτίβο Abstract Factory για να ορίσει ποια υλοποίηση θα επιλεγεί για κάποιο αφαιρετικό μοντέλο
19
19 Δομικά Στοιχεία του Σχεδιαστικού Μοτίβου Bridge Κλάση Abstraction (Abstract class) –Ορίζει τη διαπροσωπία του αφαιρετικού μοντέλου –Διατηρεί μια αναφορά σε ένα αντικείμενο υλοποίησης Κλάση RefinedAbstraction –Επεκτείνει τη διαπροσωπία που ορίζεται από τη κλάση Abstraction Κλάση Implementor (Abstract Class) –Ορίζει τη διαπροσωπία για τις κλάσεις υλοποιήσεων. Αυτή η διαπροσωπία δεν είναι κατ’ ανάγκη ίδια με αυτή του αφαιρετικού μοντέλου. Στη πράξη μάλιστα αυτές οι δύο διαπροσωπίες είναι αρκετά διαφορετικές. Συνήθως, η διαπροσωπία που της κλάσης Implementor ορίζει συγκεκριμένες λειτουργίες, ενώ η διαπροσωπία της κλάσης Abstraction ορίζει λειτουργίες υψηλού επιπέδου που υλοποιούνται με τις συγκεκριμένες λειτουργίες που ορίζει η κλάση Implementor Κλάση ConcreteImplementor –Υλοποιεί τη διαπροσωπία της κλάσης Implementor
20
20 Bridge – Διάγραμμα Κλάσης
21
21 Bridge - Παράδειγμα // "Abstraction" class Abstraction { protected Implementor implementor; // Property public Implementor Implementor { set{ implementor = value; } } public virtual void Operation() { implementor.Operation(); } } // "Implementor" abstract class Implementor { public abstract void Operation(); } // "RefinedAbstraction" class RefinedAbstraction : Abstraction { public override void Operation() { implementor.Operation(); } }
22
22 Bridge - Παράδειγμα // "ConcreteImplementorA" class ConcreteImplementorA : Implementor { public override void Operation() { Console.WriteLine("ConcreteImplementorA Operation"); } } // "ConcreteImplementorB" class ConcreteImplementorB : Implementor { public override void Operation() { Console.WriteLine("ConcreteImplementorB Operation"); } }
23
23 Bridge – Παράδειγμα Πελάτη class MainApp { static void Main() { Abstraction ab = new RefinedAbstraction(); // Set implementation and call ab.Implementor = new ConcreteImplementorA(); ab.Operation(); // Change implemention and call ab.Implementor = new ConcreteImplementorB(); ab.Operation(); // Wait for user Console.Read(); } } Output ConcreteImplementorA Operation ConcreteImplementorB Operation
24
24 Σχεδιαστικό Μοτίβο Composite Σκοπός –Ο σκοπός αυτού του Σχεδιαστικού Μοτίβου είναι να μπορούμε να διαχειριζόμαστε αντικείμενα, και συνθέσεις αντικειμένων με ένα ομοιογενή τρόπο Εφαρμογή –Τα αντικείμενα συντίθενται αναδρομικά –Δεν υπάρχει διαφορά στη διαχείριση ενός απλού αντικειμένου ή κάποιου σύνθετου αντικειμένου (σύνθετα αντικείμενα μπορούν να συμμετέχουν σε συνθέσεις με άλλα αντικείμενα) –Σύνθετα αντικείμενα διαχειρίζονται σαν μια συλλογή από ιδιαίτερα και ξεχωριστά αντικείμενα
25
25 Composite – Διάγραμμα Κλάσης
26
26 Composite - Σχόλια Επακόλουθα +Ομοιομορφία: Όλα τα αντικείμενα σε κάποια σύνθετη κατασκευη τα διαχειριζόμαστε με τον ίδιο τρόπο +Επεκτασιμότητα: Μπορούμε να κατασκευάσουμε νέες συνθέσεις από υπάρχοντα αντικείμενα – Λειτουργικό κόστος: Για τη κατασκευή ενός σύνθετου αντικειμένου μπορεί να χρειαστούμε πολλά άλλα αντικείμενα Σχόλια Υλοποίησης –Τα συνιστώντα μέρη γνωρίζουν το αντικείμενο που περιγράφει τη σύνθεση (Do Components know their parents)? –Κοινή διαπροσωπία για τα απλά και τα σύνθετα αντικείμενα? –Τα σύνθετα αντικείμενα περιέχουν μια αναφορά (reference) για κάθε ένα από τα συνιστώντα αντικείμενα (δεν χρειάζεται να δεσμεύσουμε μνήμη στο σύνθετο αντικείμενο για τα μέρη του) –Που και ποιο αντικείμενο έχει την ευθύνη για τη διαγραφή των συνιστώντων αντικειμένων
27
27 Composite - Παράδειγμα
28
28 Composite – Παράδειγμα Πελάτη Currency CompositeEquipment::NetPrice() { Iterator * i = getIterator(); Currency total = 0; for (i->First(); !i->IsDone(); i->Next()) total += i->CurrentItem()->NetPrice(); delete i; return total; } // and in the client code … (e.g. in main) Cabinet* cabinet = new Cabinet("PC Cabinet"); Chassis* chassis = new Chassis("PC Chassis"); cabinet->Add( chassis ); Bus* bus = new Bus ("MCA Bus"); bus ->Add( new Card("16Mbs Token Ring") ); chassis->Add( bus ); chassis->Add( new FloppyDisk("3.5 floppy") ); cout NetPrice() << endl;
29
29 Σχεδιαστικό Μοτίβο Façade Façade
30
30 Façade
31
31 Façade - Παράδειγμα
32
32 Σχεδιαστικό Μοτίβο Proxy Αυτό το Σχεδιαστικό Μοτίβο επιτρέπει τη δημιουργία ενός «υποκατάστατου» αντικειμένου το οποίο κρατά μια αναφορά (reference) για κάποιο αντικείμενο, και αυτό το «υποκατάστατο» ελέγχει την προσπέλαση στο αντικείμενο για το οποίο δρα σαν «υποκατάστατο» Το μοτίβο αυτό είναι χρήσιμο όταν κάποια λειτουργία παίρνει πολύ χρόνο να εκτελεσθεί, το «υποκατάστατο» αντικείμενο μπορεί να στέλνει μηνύματα για τη πρόοδο της λειτουργίας πίσω στο κώδικα πελάτη Το «υποκατάστατο» αντικείμενο μπορεί επίσης να παρέχει συμπληρωματικές λειτουργίες για λογαριασμό του αντικειμένου για το οποίο δρά σαν «υποκατάστατο». Για παράδειγμα το «υποκατάστατο» αντικείμενο μπορεί να προσφέρει συμπληρωματικές λειτουργίες σχετικές με ασφάλεια, έλεγχο προσπέλασης, RPC κλπ.
33
33 Δομικά Στοιχεία του Σχεδιαστικού Μοτίβου Proxy Κλάση Proxy –Διατηρεί μια αναφορά (reference) στο «πραγματικό» αντικείμενο και ελέγχει τη προσπέλαση σε αυτό το «πραγματικό» αντικείμενο. –Παρέχει μια διαπροσωπία που είναι όμοια με αυτή του αντικειμένου που δρα σαν υποκατάστατο –Ελέγχει τη πρόσβαση στο αντικείμενο και είναι ίσως υπεύθυνη για να το δημιουργεί και να το καταστρέφει –Παρέχει συμπληρωματικές λειτουργίες ανάλογα με το τι τύπος «υποκατάστατου» είναι. Μπορούμε να ορίσουμε τρεις βασικούς τύπους υποκατάστατων αντικειμένων: remote proxies (απόκεντρα υποκατάστατα) είναι επιφορτισμένα να λαμβάνουν μια κλήση και στη συνέχεια να την κωδικοποιούν και να την στέλνουν στο «πραγματικό» αντικείμενο το οποίο βρίσκεται σε κάποιο άλλο υπολογιστικό σύστημα ή address space virtual proxies (εικονικά υποκατάστατα) διατηρούν πληροφορίες για τη κατάσταση του πραγματικού αντικειμένου έτσι ώστε να είναι σε θέση να αναβάλλουν όσο το δυνατόν την προσπέλαση στο πραγματικό αντικείμενο protection proxies (υποκατάστατα προστασίας) ελέγχει εάν ο καλών έχει τα κατάλληλα διαπιστευτήρια για να καλέσει το πραγματικό αντικείμενο και τις λειτουργίες που αυτό προσφέρει Κλάση Subject –Ορίζει μια κοινή διαπροσωπεία για τη Proxy και τη κλάση RealSubject έτσι ώστε η κλάση Proxy να μπορεί να χρησιμοποιηθεί όπου μπορεί να χρησιμοποιηθεί και η κλάση RealSubject Κλάση RealSubject – Ορίζει το «πραγματικό» αντικείμενο που τελικά θα προσπελασθεί και θα προσφέρει τις αντίστοιχες υπηρεσίες
34
34 Proxy – Διάγραμμα Κλάσης
35
35 Proxy - Παράδειγμα // "Subject" abstract class Subject { public abstract void Request(); } // "RealSubject" class RealSubject : Subject { public override void Request() { Console.WriteLine("Called RealSubject.Request()"); } } // "Proxy" class Proxy : Subject { RealSubject realSubject; public override void Request() { // Use 'lazy initialization' if (realSubject == null) { realSubject = new RealSubject(); } realSubject.Request(); } }
36
36 Proxy – Παράδειγμα Πελάτη class MainApp { static void Main() { // Create proxy and request a service Proxy proxy = new Proxy(); proxy.Request(); // Wait for user Console.Read(); } } Αποτέλεσμα: Called RealSubject.Request()
Παρόμοιες παρουσιάσεις
© 2024 SlidePlayer.gr Inc.
All rights reserved.