Μία από τις πιο σημαντικές αρχές στην ανάπτυξη λογισμικού είναι η αρχή του ανοιχτού-κλειστού σχεδιασμού. Αυτή η αρχή σχεδιασμού τονίζει ότι οι κλάσεις πρέπει να είναι ανοιχτές για επέκταση, αλλά κλειστές για τροποποίηση. Το σχέδιο του διακοσμητή ενσωματώνει την αρχή σχεδίασης ανοιχτού-κλειστού.
Με το μοτίβο σχεδίασης διακοσμητή, μπορείτε εύκολα να επεκτείνετε μια τάξη δίνοντάς της νέα συμπεριφορά χωρίς να τροποποιήσετε τον υπάρχοντα κώδικα. Το μοτίβο διακοσμητή το κάνει δυναμικά κατά τη διάρκεια της εκτέλεσης, χρησιμοποιώντας σύνθεση. Αυτό το σχέδιο σχεδίασης είναι γνωστό ως μια ευέλικτη εναλλακτική στη χρήση της κληρονομικότητας για την επέκταση της συμπεριφοράς.
Πώς λειτουργεί το μοτίβο σχεδίασης διακοσμητή;
Αν και το μοτίβο του διακοσμητή είναι μια εναλλακτική ταξική κληρονομιά, ενσωματώνει ορισμένες πτυχές κληρονομικότητας στο σχεδιασμό του. Μια βασική πτυχή του μοτίβου του διακοσμητή είναι ότι όλες οι κατηγορίες του σχετίζονται, είτε άμεσα είτε έμμεσα.
Ένα τυπικό μοτίβο σχεδιασμού διακοσμητή έχει την ακόλουθη δομή:
Από το παραπάνω διάγραμμα τάξης μπορείτε να δείτε ότι το μοτίβο διακοσμητή έχει τέσσερις κύριες κατηγορίες.
Συστατικό: Αυτή είναι μια αφηρημένη κλάση (ή διεπαφή), η οποία χρησιμεύει ως ο υπερτύπος για το μοτίβο του διακοσμητή.
Συστατικό σκυροδέματος: Αυτά είναι τα αντικείμενα που μπορείτε να διακοσμήσετε με διαφορετικές συμπεριφορές κατά την εκτέλεση. Κληρονομούν από τη διεπαφή στοιχείων και υλοποιούν τις αφηρημένες λειτουργίες της.
Διακοσμητής: αυτή η κλάση είναι αφηρημένη και έχει τον ίδιο υπερτύπο με το αντικείμενο που θα διακοσμήσει. Στο διάγραμμα κλάσεων, θα δείτε δύο σχέσεις μεταξύ των κλάσεων στοιχείων και διακοσμητών. Η πρώτη σχέση είναι κληρονομική. κάθε διακοσμητής είναι ένα συστατικό. Η δεύτερη σχέση είναι αυτή της σύνθεσης. κάθε διακοσμητής έχει ένα (ή τυλίγει ένα) συστατικό.
ConcreteDecorator: Αυτοί είναι οι μεμονωμένοι διακοσμητές που δίνουν σε ένα συστατικό μια συγκεκριμένη συμπεριφορά. Θα πρέπει να σημειώσετε ότι κάθε διακοσμητής σκυροδέματος έχει μια μεταβλητή εμφάνισης που περιέχει μια αναφορά σε ένα στοιχείο.
Εφαρμογή του μοτίβου σχεδίασης διακοσμητή σε Java
Ένα δείγμα εφαρμογής παραγγελίας πίτσας μπορεί να δείξει επαρκώς πώς να χρησιμοποιήσετε το μοτίβο διακοσμητή για την ανάπτυξη εφαρμογών. Αυτή η εφαρμογή δείγματος πίτσας επιτρέπει στους πελάτες να παραγγείλουν πίτσες με πολλαπλές επικαλύψεις. Η πρώτη κατηγορία του μοτίβου διακοσμητή είναι η διεπαφή πίτσας:
δημόσιοδιεπαφήΠίτσα{
δημόσιοαφηρημένη Σειρά περιγραφή();
δημόσιοαφηρημένηδιπλόκόστος();
}
Η διεπαφή Pizza είναι η κλάση στοιχείων. Έτσι, μπορείτε να δημιουργήσετε μία ή περισσότερες συγκεκριμένες κατηγορίες από αυτό. Η εταιρεία πίτσας φτιάχνει δύο βασικούς τύπους πίτσας, με βάση τη ζύμη τους. Ένα είδος πίτσας έχει ζύμη μαγιάς:
δημόσιοτάξηYeastCrustPizzaυλοποιείΠίτσα{
@Καταπατώ
δημόσιο Σειρά περιγραφή(){
ΕΠΙΣΤΡΟΦΗ"Ζύμη πίτσας με μαγιά";
}
@Καταπατώ
δημόσιοδιπλόκόστος(){
ΕΠΙΣΤΡΟΦΗ18.00;
}
}
Η YeastCrustPizza είναι το πρώτο σκυρόδεμα Κλάση Java της διεπαφής Pizza. Το άλλο είδος πίτσας που διατίθεται είναι το flatbread:
δημόσιοτάξηFlatbreadCrustPizzaυλοποιείΠίτσα{
@Καταπατώ
δημόσιο Σειρά περιγραφή(){
ΕΠΙΣΤΡΟΦΗ"Ζύμη πίτσας με πλακέ ψωμί";
}
@Καταπατώ
δημόσιοδιπλόκόστος(){
ΕΠΙΣΤΡΟΦΗ15.00;
}
}
Η κλάση FlatbreadCrustPizza είναι το δεύτερο συγκεκριμένο συστατικό και, όπως και η κλάση YeastCrustPizza, υλοποιεί όλες τις αφηρημένες λειτουργίες της διεπαφής Pizza.
Οι Διακοσμητές
Η τάξη του διακοσμητή είναι πάντα αφηρημένη, επομένως δεν μπορείτε να δημιουργήσετε μια νέα παρουσία απευθείας από αυτήν. Αλλά είναι απαραίτητο να δημιουργηθεί μια σχέση μεταξύ των διαφορετικών διακοσμητών και των στοιχείων που θα διακοσμήσουν.
δημόσιοαφηρημένητάξηToppingDecoratorυλοποιείΠίτσα{
δημόσιο Σειρά περιγραφή(){
ΕΠΙΣΤΡΟΦΗ"Άγνωστο κάλυμμα";
}
}
Η κλάση ToppingDecorator αντιπροσωπεύει την κλάση διακοσμητή σε αυτό το δείγμα εφαρμογής. Τώρα η εταιρεία πίτσας μπορεί να δημιουργήσει πολλά διαφορετικά toppings (ή διακοσμητές), χρησιμοποιώντας την κατηγορία ToppingDecorator. Ας υποθέσουμε ότι μια πίτσα μπορεί να έχει τρεις διαφορετικούς τύπους επικαλύψεων, δηλαδή τυρί, πεπερόνι και μανιτάρια.
Επικάλυψη τυριού
δημόσιοτάξηΤυρίεκτείνεταιToppingDecorator{
ιδιωτικός Πίτσα πίτσα?δημόσιοΤυρί(πίτσα πίτσα){
Αυτό.pizza = πίτσα;
}@Καταπατώ
δημόσιο Σειρά περιγραφή(){
ΕΠΙΣΤΡΟΦΗ pizza.description() + ", Επικάλυψη τυριού";
}
@Καταπατώ
δημόσιοδιπλόκόστος(){
ΕΠΙΣΤΡΟΦΗπίτσα.κόστος() + 2.50;
}
}
Τοπινγκ πεπερόνι
δημόσιοτάξηΠεπερόνιεκτείνεταιToppingDecorator{
ιδιωτικός Πίτσα πίτσα?δημόσιοΠεπερόνι(πίτσα πίτσα){
Αυτό.pizza = πίτσα;
}@Καταπατώ
δημόσιο Σειρά περιγραφή(){
ΕΠΙΣΤΡΟΦΗ pizza.description() + ", Pepperoni Topping";
}
@Καταπατώ
δημόσιοδιπλόκόστος(){
ΕΠΙΣΤΡΟΦΗπίτσα.κόστος() + 3.50;
}
}
Επικάλυψη μανιταριών
δημόσιοτάξηΜανιτάριεκτείνεταιToppingDecorator{
ιδιωτικός Πίτσα πίτσα?δημόσιοΜανιτάρι(πίτσα πίτσα){
Αυτό.pizza = πίτσα;
}
@Καταπατώ
δημόσιο Σειρά περιγραφή(){
ΕΠΙΣΤΡΟΦΗ pizza.description() + ", κάλυμμα μανιταριών";
}
@Καταπατώ
δημόσιοδιπλόκόστος(){
ΕΠΙΣΤΡΟΦΗπίτσα.κόστος() + 4.50;
}
}
Τώρα έχετε μια απλή εφαρμογή που υλοποιείται χρησιμοποιώντας το μοτίβο σχεδίασης διακοσμητή. Εάν ένας πελάτης παραγγείλει μια πίτσα με ζύμη με τυρί και πεπερόνι, ο κωδικός δοκιμής για αυτό το σενάριο θα έχει ως εξής:
δημόσιοτάξηΚύριος{
δημόσιοστατικόςκενόςκύριος(String[] args){
Πίτσα πίτσα1 = νέος YeastCrustPizza();
πίτσα1 = νέος Πεπερόνι (πίτσα 1);
πίτσα1 = νέος Τυρί (πίτσα 1);
System.out.println (pizza1.description() + " $" + pizza1.cost());
}
}
Η εκτέλεση αυτού του κώδικα θα παράγει την ακόλουθη έξοδο στην κονσόλα:
Όπως μπορείτε να δείτε, η έξοδος αναφέρει το είδος της πίτσας μαζί με το συνολικό κόστος της. Η πίτσα ξεκίνησε ως πίτσα με κρούστα μαγιάς για 18,00 $, αλλά με το μοτίβο του διακοσμητή, η εφαρμογή μπόρεσε να προσθέσει νέα χαρακτηριστικά και το κατάλληλο κόστος στην πίτσα. Έτσι, δίνοντας στην πίτσα νέα συμπεριφορά χωρίς να αλλοιωθεί ο υπάρχων κώδικας (η πίτσα με κρούστα μαγιάς).
Με το μοτίβο διακοσμητή, μπορείτε επίσης να εφαρμόσετε την ίδια συμπεριφορά σε ένα αντικείμενο όσες φορές θέλετε. Εάν ένας πελάτης παραγγείλει μια πίτσα με τα πάντα και λίγο επιπλέον τυρί, μπορείτε να ενημερώσετε την κύρια κατηγορία με τον ακόλουθο κώδικα για να αντικατοπτρίζεται αυτό:
Πίτσα πίτσα2 = νέος YeastCrustPizza();
πίτσα2 = νέος Πεπερόνι (πίτσα 2);
πίτσα2 = νέος Τυρί (πίτσα 2);
πίτσα2 = νέος Τυρί (πίτσα 2);
πίτσα2 = νέος Μανιτάρια (πίτσα2);System.out.println (pizza2.description() + " $" + pizza2.cost());
Η ενημερωμένη εφαρμογή θα παράγει την ακόλουθη έξοδο στην κονσόλα:
Τα πλεονεκτήματα της χρήσης του μοτίβου σχεδίασης διακοσμητή
Τα δύο κύρια πλεονεκτήματα της χρήσης του σχεδίου του διακοσμητή είναι η ασφάλεια και η ευελιξία. Το μοτίβο διακοσμητή σάς επιτρέπει να αναπτύξετε πιο ασφαλή κώδικα χωρίς να παρεμβαίνετε σε προϋπάρχοντα ασφαλή κώδικα. Αντίθετα, επεκτείνει τον υπάρχοντα κώδικα μέσω της σύνθεσης. Αποτρέπει αποτελεσματικά την εισαγωγή νέων σφαλμάτων ή ανεπιθύμητων παρενεργειών.
Λόγω της σύνθεσης, ένας προγραμματιστής έχει επίσης μεγάλη ευελιξία όταν χρησιμοποιεί το μοτίβο διακοσμητή. Μπορείτε να εφαρμόσετε ένα νέο διακοσμητή ανά πάσα στιγμή για να προσθέσετε νέα συμπεριφορά, χωρίς να τροποποιήσετε τον υπάρχοντα κώδικα και να διαταράξετε την εφαρμογή.