Μοτίβα σχεδίασης - Ένας γρήγορος οδηγός για το μοτίβο παρατηρητή.

Το πρότυπο παρατηρητή είναι ένα πολύ συνηθισμένο πρότυπο. Στην πραγματικότητα, είναι τόσο συνηθισμένο που τυποποιείται σε πολλές γλώσσες / βιβλιοθήκες προγραμματισμού. Στην Java, υπάρχει injava.util.Observer (καταργείται στην Java 9). Στην Python, όσο πιο κοντά πλησιάζει η apip, εγκαταστήστε παρατηρητή προτύπων. Στην C ++, μπορούμε μερικές φορές να χρησιμοποιήσουμε τη βιβλιοθήκη ώθησης, ακριβέστερα #include . Ωστόσο, χρησιμοποιείται ευρέως στη βιομηχανία ως επί παραγγελία λύση. Για να μπορέσουμε να το χρησιμοποιήσουμε σωστά και να κατανοήσουμε την πολυπλοκότητά του, πρέπει να το βουτήξουμε και να το εξερευνήσουμε.

Το πρότυπο παρατηρητή κατατάσσεται στα πρότυπα σχεδιαστικής συμπεριφοράς. Τα σχέδια σχεδιαστικής συμπεριφοράς αφορούν ειδικότερα την επικοινωνία μεταξύ τάξεων / αντικειμένων. [από τα μοτίβα σχεδιασμού εξήγησε απλώς]

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

Βήμα 1 - Λέξεις-κλειδιά

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

  1. Θέμα: Θεωρείται ως φύλαξη πληροφοριών, δεδομένων ή επιχειρηματικής λογικής.
  2. Εγγραφή / Επισύναψη: Οι παρατηρητές εγγράφονται στο θέμα επειδή επιθυμούν να ενημερωθούν όταν υπάρξει αλλαγή.
  3. Γεγονός: Τα γεγονότα δρουν ως έναυσμα στο θέμα, έτσι ώστε να ειδοποιούνται όλοι οι παρατηρητές.
  4. Ειδοποίηση: Ανάλογα με την εφαρμογή, το θέμα μπορεί να "ωθήσει" τις πληροφορίες στους παρατηρητές, ή οι παρατηρητές μπορεί να "τραβήξουν" εάν χρειάζονται πληροφορίες από το θέμα.
  5. Ενημέρωση: Οι παρατηρητές ενημερώνουν την κατάστασή τους ανεξάρτητα από άλλους παρατηρητές, ωστόσο η κατάσταση τους μπορεί να αλλάξει ανάλογα με την εκδήλωση που πυροδότησε.

Βήμα 2 - Διάγραμμα

Αφήστε να χωρίσετε αυτό το σχέδιο σε διαφορετικές κλάσεις για να το απλοποιήσετε λίγο.

  • Τα ConcreteObservers είναι κλάσεις που περιέχουν πληροφορίες που αφορούν την τρέχουσα παρουσία. Η λειτουργία ενημέρωσης καλείται από τη λειτουργία ειδοποίησης () του θέματος. Οι παρατηρητές ενημερώνονται ανεξάρτητα με βάση την τρέχουσα κατάσταση τους.
  • Ο παρατηρητής είναι η μητρική τάξη των συγκεκριμένων παρατηρητών. Περιέχει ένα στιγμιότυπο υποκειμένου. Όταν ένα παρατηρητής αρχικοποιηθεί, καταγράφει / συνδέεται με το θέμα.
  • Η τάξη Subject έχει έναν κατάλογο ή μια συλλογή παρατηρητών. Όταν ένα συμβάν ενεργοποιείται, καλεί τη λειτουργία ειδοποίησης (), η οποία βγαίνει από όλους τους παρατηρητές, καλώντας τη λειτουργία ενημέρωσης.

Βήμα 3 - Κωδικοποιήστε με Παράδειγμα

Θα πρότεινα να αντιγράψω την τάξη κώδικα ανά τάξη από το αποθετήριο git μου "Andreas Poyias" ή τα αποσπάσματα παρακάτω (με τη σειρά που παρέχεται) και να τα επικολλήσω σε οποιονδήποτε από τους διαθέσιμους σε απευθείας σύνδεση εκδότες C ++ όπως c ++ shell, jdoodle, onlineGDB και τρέξιμο να παρακολουθεί την έξοδο. Στη συνέχεια διαβάστε τα σχόλια ή την περιγραφή παρακάτω. Πάρτε το χρόνο σας, διαβάστε προσεκτικά (δηλαδή ένα λεπτό, όχι λιγότερο και όχι περισσότερο).

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

  • Το παιχνίδι είναι το θέμα και οι υποστηρικτές είναι οι παρατηρητές.
  • Όλοι οι παρατηρητές επισυνάπτονται / εγγράφονται στο θέμα και ενημερώνονται όταν βαθμολογούνται οι ποδοσφαιρικές ομάδες τους (η εκδήλωση ενεργοποίησης είναι αν η ομάδα τους σκοράρει).
  • Οι παρατηρητές ενημερώνουν τη συμπεριφορά τους ανάλογα με την ειδοποίηση που έλαβε.

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

#include 
#include 
χρησιμοποιώντας τον χώρο ονομάτων std.
τάξη Θέμα {
    φορέας <παρατηρητής τάξης *> παρατηρητές;
    bool βαθμολογία? // ενεργοποίηση, συμβάν
δημόσιο:
    // καταχωρούν παρατηρητές
    άκυρη αποστολή (παρατηρητής * obs) {
        παρατηρητές.push_back (obs);
    }}
   
   // Αυτή είναι η ΕΚΔΗΛΩΣΗ
   // ορίστε το if score και ενημερώστε όλους τους παρατηρητές
   void setScored (Βαθμός bool) {
      βαθμολογία = Βαθμολογία
      κοινοποιώ();
   }}
bool getScored () {
      επιστροφή βαθμολογήθηκε?
   }}
   // κοινοποιούν ότι η εφαρμογή είναι πιο κάτω
   // έτσι ώστε η δέσμη ενεργειών να συντάσσεται και να εκτελείται
   void notify ();
},

Παρατηρητής
Αυτή η τάξη εξαρτάται από το θέμα στο οποίο είναι καταχωρημένο. Όταν οι συγκεκριμένοι παρατηρητές αρχικοποιηθούν, αυτοί συνδέονται με το θέμα. Σε αυτό το παράδειγμα, η κατάσταση κάθε παρατηρητή είναι ο ενθουσιασμός του Levelabout του παιχνιδιού.

class παρατηρητή
{
    Θέμα * subj;
    int excitementLevel; // κατάσταση
  δημόσιο:
    Παρατηρητής (Θέμα * mod, int excLevel)
    {
        subj = mod;
        excitementLevel = excLevel;
        // Οι παρατηρητές εγγράφονται / συνδέονται με το θέμα
        subj-> επισυνάψτε (αυτό)?
    }}
    εικονική κενή ενημέρωση () = 0;
  προστασία:
    Θέμα * getSubject () {
       επιστροφή subj;
    }}
    άκυρη setExcitementLevel (int excLevel) {
       excitementLevel = excLevel;
    }}
    int getExcitementLevel () {
       επιστροφή excitementLevel;
    }}
},

Αυτή είναι η δήλωση Submitted :: notify () και όπως προαναφέρθηκε, η δουλειά της είναι να ενημερώνει όλους τους παρατηρητές για την ενημέρωση της κατάστασής τους.

void Θέμα :: notify () {
  για (int i = 0, i <παρατηρητές.size (), i ++)
    παρατηρητές [i] -> ενημέρωση ();
}}

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

class Old_ConcreteObserver: δημόσιος παρατηρητής
{
   δημόσιο:
     // Καλεί τον κατασκευαστή γονέων να εγγραφεί με το θέμα
     Old_ConcreteObserver (Θέμα * mod, int div)
        : Παρατηρητής (mod, div) {}
     // Για τους ηλικιωμένους, αν το επίπεδο ενθουσιασμού
     // είναι πάνω από 150 διατρέχουν κίνδυνο καρδιακής προσβολής
     άκυρη ενημέρωση ()
     {
        bool βαθμολογία = getSubject () -> getScored ();
        setExcitementLevel (getExcitementLevel () + 1).
        if (βαθμολογία && getExcitementLevel ()> 150)
        {
          cout << "Η ομάδα του παλαιού παρατηρητή σκόραρε !!"
               << "Το επίπεδο ενθουσιασμού του είναι"
               << getExcitementLevel ()
               << "προσέξτε από καρδιακές προσβολές!" << endl;
        }αλλού{
          cout << "Η ομάδα δεν σκόραρε Yeeeih τίποτα να ανησυχείτε για"
               << endl;
        }}
    } // end update ()
},
class Young_ConcreteObserver: δημόσιο παρατηρητή
{
   δημόσιο:
     // Καλεί τον κατασκευαστή γονέων να εγγραφεί με το θέμα
     Young_ConcreteObserver (Θέμα * mod, int div)
       : Παρατηρητής (mod, div) {}
     // Για τους ηλικιωμένους, αν το επίπεδο ενθουσιασμού
     // είναι πάνω από 100 διατρέχουν κίνδυνο καρδιακής προσβολής
     άκυρη ενημέρωση ()
     {
        bool βαθμολογία = getSubject () -> getScored ();
        setExcitementLevel (getExcitementLevel () + 1).
        if (βαθμολογία && getExcitementLevel ()> 100)
        {
          cout << "Η ομάδα του Young Observer σκόραρε !!"
               << "Το επίπεδο ενθουσιασμού του είναι"
               << getExcitementLevel ()
               << "Μην πίνετε και οδηγείτε!" << endl;
        }αλλού{
          cout << "Η ομάδα δεν σκοράρει. Yeeh τίποτα δεν πρέπει να ανησυχείτε για"
               << endl;
       }}
    } // end update ()
},

Κύρια λειτουργία
Οι συγκεκριμένοι παρατηρητές καταχωρούν τον εαυτό τους στην υπόθεση του υποκειμένου. Η κατάσταση τους είναι το επίπεδο ενθουσιασμού που είναι η δεύτερη παράμετρος. Όταν ενεργοποιηθεί το συμβάν "subj.setScored (true)", τότε ζητείται η υποβολήSubject :: notify () για την ενημέρωση των εγγεγραμμένων παρατηρητών. Στο παρακάτω σενάριο, έχουμε τρεις παρατηρητές, οι νεαροί είναι υπερβολικοί και διατρέχουν τον κίνδυνο να πίνουν και να οδηγήσουν, το oldObs1 είναι επίσης υπερβολικά υπερβολικό και τρέχει διαφορετικό κίνδυνο (καρδιακής προσβολής). Τέλος, ο νεαρός Ομπρός2, ο οποίος είναι επίσης νέος ως ο πρώτος, δεν έχει τίποτα να ανησυχεί γιατί δεν είναι υπερβολικός.

Είναι σημαντικό να παρατηρήσουμε ότι οι τρεις παρατηρητές ενημερώθηκαν ανεξάρτητα με βάση την κατάσταση τους (επίπεδο ενθουσιασμού) και τον τύπο τους (νέους ή ηλικιωμένους).
int main () {
   Subject subj;
   Young_ConcreteObserver youngObs1 (& subj, 100);
   Old_ConcreteObserver oldObs1 (& subj, 150);
   Young_ConcreteObserver youngObs2 (& subj, 52);
   subj.setScored (true);
}}
// Έξοδος
// Η ομάδα του Young Observer σκόραρε !! Το επίπεδο ενθουσιασμού του είναι 101
// Μην πίνετε και οδηγείτε!
// Η ομάδα του Old Observer σκόραρε !! Το επίπεδο ενθουσιασμού του είναι 151 ρολόγια
// από καρδιακές προσβολές! Η ομάδα δεν σκόραρε.
// Yeeh τίποτα δεν πρέπει να ανησυχείτε

Υπάρχουν μερικά οφέλη για τη χρήση του σχεδίου Observer και μερικά σημεία που πρέπει να σημειωθούν όταν πρόκειται να προσεγγιστεί αυτό το μοτίβο [Learning Python Design Patterns].

  • Το μοτίβο Observer παρέχει ένα σχέδιο όπου το θέμα και ο παρατηρητής είναι χαλαρά συνδεδεμένα. Το θέμα δεν χρειάζεται να γνωρίζει για την κλάση ConcreteObserver. Οποιοσδήποτε νέος Παρατηρητής μπορεί να προστεθεί ανά πάσα στιγμή. Δεν χρειάζεται να τροποποιήσετε το Θέμα όταν προστίθεται ένας νέος Παρατηρητής. Οι παρατηρητές και τα θέματα δεν είναι δεμένα και είναι ανεξάρτητα το ένα από το άλλο, επομένως, οι αλλαγές στο Θέμα ή τον Παρατηρητή δεν θα επηρεάσουν το ένα το άλλο.
  • Δεν υπάρχει επιλογή για σύνθεση, καθώς η διεπαφή του Observer μπορεί να δημιουργηθεί ως παράδοση.
  • Εάν ο Παρατηρητής καταχραστεί, μπορεί εύκολα να προσθέσει πολυπλοκότητα και να οδηγήσει σε προβλήματα επιδόσεων.
  • Οι ειδοποιήσεις μπορεί να είναι αναξιόπιστες και μπορεί να έχουν ως αποτέλεσμα συνθήκες φυλής ή ασυνέπεια.

Το επόμενο blog θα είναι ένας γρήγορος οδηγός για το μοτίβο σχεδίασης Bridge. Πρόκειται για ένα σχέδιο δομικής σχεδίασης το οποίο χρησιμοποιείται αρκετά στον κλάδο. Μην ξεχάσετε να αρέσετε / χτυπήσετε το blog-post μου και να ακολουθήσετε το λογαριασμό μου. Αυτό είναι να μου δώσει την ικανοποίηση ότι βοήθησα μερικούς συντροφικούς προγραμματιστές και με ώθησε να συνεχίσω να γράφω. Εάν υπάρχει ένα συγκεκριμένο μοτίβο σχεδίασης για το οποίο θα θέλατε να μάθετε τότε ενημερώστε με για να μπορέσω να το σας προσφέρω στο μέλλον.

Άλλοι γρήγοροι οδηγοί για τα σχέδια:

  1. Design Patterns - Ένας γρήγορος οδηγός για το αφηρημένο εργοστάσιο.
  2. Μοτίβα σχεδίασης - Ένας γρήγορος οδηγός για το Bridge Pattern.
  3. Μοτίβα Σχεδιασμού - Ένας γρήγορος οδηγός για το μοτίβο του Builder.
  4. Μοτίβα σχεδίασης - Ένας γρήγορος οδηγός για το μοτίβο διακοσμητή.
  5. Μοτίβα Σχεδιασμού - Ένας γρήγορος οδηγός για το Πρότυπο Πρόσοψης.
  6. Μοτίβα σχεδίασης - Ένας γρήγορος οδηγός για το μοτίβο παρατηρητή.
  7. Μοτίβα Σχεδιασμού - Ένας γρήγορος οδηγός για το Singleton Pattern.