Ως καλός προγραμματιστής JavaScript, προσπαθείτε να γράψετε καθαρό, υγιή και διατηρήσιμο κώδικα. Επιλύετε ενδιαφέρουσες προκλήσεις που, αν και μοναδικές, δεν απαιτούν απαραίτητα μοναδικές λύσεις. Πιθανότατα να έχετε γράψει κώδικα που μοιάζει με τη λύση ενός εντελώς διαφορετικού προβλήματος που έχετε αντιμετωπίσει στο παρελθόν. Μπορεί να μην το γνωρίζετε, αλλά έχετε χρησιμοποιήσει JavaScript μοτίβο σχεδίασης . Τα μοτίβα σχεδιασμού είναι επαναχρησιμοποιήσιμες λύσεις σε προβλήματα που εμφανίζονται συνήθως στη σχεδίαση λογισμικού.
Κατά τη διάρκεια ζωής μιας γλώσσας, πολλές τέτοιες επαναχρησιμοποιήσιμες λύσεις γίνονται και δοκιμάζονται από μεγάλο αριθμό προγραμματιστών από την κοινότητα αυτής της γλώσσας. Λόγω αυτής της συνδυασμένης εμπειρίας πολλών προγραμματιστών, τέτοιες λύσεις είναι τόσο χρήσιμες επειδή μας βοηθούν να γράψουμε κώδικα με βελτιστοποιημένο τρόπο, ενώ ταυτόχρονα επιλύουμε το πρόβλημα που αντιμετωπίζουμε.
Τα βασικά οφέλη που έχουμε από τα πρότυπα σχεδίασης είναι τα ακόλουθα:
Γνωρίζω ότι είστε έτοιμοι να προχωρήσετε σε αυτό το σημείο, αλλά προτού να μάθετε τα πάντα σχετικά με τα μοτίβα σχεδίασης, ας δούμε μερικά βασικά JavaScript.
Το JavaScript είναι μια από τις πιο δημοφιλείς γλώσσες προγραμματισμού για ανάπτυξη ιστού σήμερα. Αρχικά δημιουργήθηκε ως ένα είδος «κόλλας» για διάφορα στοιχεία HTML που εμφανίζονται, γνωστά ως γλώσσα scripting από την πλευρά του πελάτη, για ένα από τα αρχικά προγράμματα περιήγησης στο Web. Ονομάστηκε Netscape Navigator, θα μπορούσε να εμφανίζει στατικό HTML μόνο εκείνη τη στιγμή. Όπως μπορείτε να υποθέσετε, η ιδέα μιας τέτοιας γλώσσας σεναρίων οδήγησε σε πολέμους του προγράμματος περιήγησης μεταξύ των μεγάλων παικτών στη βιομηχανία ανάπτυξης του προγράμματος περιήγησης τότε, όπως η Netscape Communications (σήμερα Mozilla), η Microsoft και άλλοι.
Καθένας από τους μεγάλους παίκτες ήθελε να προωθήσει τη δική του εφαρμογή αυτής της γλώσσας σεναρίου, οπότε η Netscape έφτιαξε τη JavaScript (στην πραγματικότητα, έκανε ο Brendan Eich), η Microsoft έκανε το JScript και ούτω καθεξής. Όπως μπορείτε να δείτε, οι διαφορές μεταξύ αυτών των εφαρμογών ήταν εξαιρετικές, οπότε η ανάπτυξη για προγράμματα περιήγησης ιστού έγινε ανά πρόγραμμα περιήγησης, με αυτοκόλλητα με την καλύτερη προβολή που συνοδεύουν μια ιστοσελίδα. Σύντομα έγινε σαφές ότι χρειαζόμασταν μια τυπική, μια λύση cross-browser που θα ενοποιεί τη διαδικασία ανάπτυξης και θα απλοποιεί τη δημιουργία ιστοσελίδων. Αυτό που βρήκαν ονομάζεται ECMAScript .
Το ECMAScript είναι μια τυποποιημένη προδιαγραφή γλώσσας δέσμης ενεργειών που προσπαθούν να υποστηρίξουν όλα τα σύγχρονα προγράμματα περιήγησης και υπάρχουν πολλές υλοποιήσεις (θα μπορούσατε να πείτε διάλεκτοι) του ECMAScript. Το πιο δημοφιλές είναι το θέμα αυτού του άρθρου, JavaScript. Από την αρχική του κυκλοφορία, το ECMAScript έχει τυποποιήσει πολλά σημαντικά πράγματα και για όσους ενδιαφέρονται περισσότερο για τις λεπτομέρειες, υπάρχει μια λεπτομερής λίστα τυποποιημένων στοιχείων για κάθε έκδοση του ECMAScript που είναι διαθέσιμη στη Wikipedia. Η υποστήριξη προγράμματος περιήγησης για εκδόσεις ECMAScript 6 (ES6) και νεότερες εκδόσεις εξακολουθεί να είναι ελλιπής και πρέπει να μεταφερθεί στο ES5 για να υποστηριχθεί πλήρως.
Προκειμένου να κατανοήσουμε πλήρως τα περιεχόμενα αυτού του άρθρου, ας κάνουμε μια εισαγωγή σε μερικά πολύ σημαντικά γλωσσικά χαρακτηριστικά που πρέπει να γνωρίζουμε πριν από την κατάδυση σε σχέδια σχεδίασης JavaScript. Αν κάποιος σας ρωτούσε 'Τι είναι το JavaScript;' μπορεί να απαντήσετε κάπου στις γραμμές:
Το JavaScript είναι μια ελαφριά, ερμηνευμένη, αντικειμενοστρεφής γλώσσα προγραμματισμού με λειτουργίες πρώτης κατηγορίας που είναι πιο γνωστές ως γλώσσα δέσμης ενεργειών για ιστοσελίδες.
Ο προαναφερθείς ορισμός σημαίνει ότι ο κώδικας JavaScript έχει χαμηλό αποτύπωμα μνήμης, είναι εύκολο να εφαρμοστεί και εύκολο να μάθει, με μια σύνταξη παρόμοια με τις δημοφιλείς γλώσσες όπως το C ++ και το Java. Είναι μια γλώσσα δέσμης ενεργειών, που σημαίνει ότι ο κώδικάς του ερμηνεύεται αντί να μεταγλωττίζεται. Έχει υποστήριξη για διαδικαστικά, αντικειμενοστραφή και λειτουργικά στυλ προγραμματισμού, γεγονός που το καθιστά πολύ ευέλικτο για προγραμματιστές.
Μέχρι στιγμής, ρίξαμε μια ματιά σε όλα τα χαρακτηριστικά που ακούγονται σαν πολλές άλλες γλώσσες εκεί έξω, οπότε ας ρίξουμε μια ματιά στο τι είναι συγκεκριμένο για το JavaScript σε σχέση με άλλες γλώσσες. Θα απαριθμήσω μερικά χαρακτηριστικά και θα δώσω τον καλύτερο δυνατό τρόπο για να εξηγήσω γιατί αξίζουν ιδιαίτερη προσοχή.
Αυτό το χαρακτηριστικό ήταν ενοχλητικό για να το καταλάβω όταν μόλις ξεκίνησα με JavaScript, καθώς ήμουν από φόντο C / C ++. Το JavaScript αντιμετωπίζει τις λειτουργίες ως πολίτες πρώτης κατηγορίας, που σημαίνει ότι μπορείτε να μεταβιβάσετε συναρτήσεις ως παραμέτρους σε άλλες λειτουργίες, όπως θα κάνατε με οποιαδήποτε άλλη μεταβλητή.
// we send in the function as an argument to be // executed from inside the calling function function performOperation(a, b, cb) { var c = a + b; cb(c); } performOperation(2, 3, function(result) { // prints out 5 console.log('The result of the operation is ' + result); })
Όπως συμβαίνει με πολλές άλλες αντικειμενοστρεφείς γλώσσες, το JavaScript υποστηρίζει αντικείμενα και ένας από τους πρώτους όρους που έρχεται στο μυαλό όταν σκεφτόμαστε αντικείμενα είναι τάξεις και κληρονομιά. Εδώ είναι λίγο δύσκολο, καθώς η γλώσσα δεν υποστηρίζει τάξεις με τη μορφή της απλής γλώσσας, αλλά χρησιμοποιεί κάτι που ονομάζεται κληρονομιά που βασίζεται σε πρωτότυπο ή σε στιγμιότυπα.
Μόλις τώρα, στο ES6, ο επίσημος όρος τάξη εισάγεται, πράγμα που σημαίνει ότι τα προγράμματα περιήγησης εξακολουθούν να μην το υποστηρίζουν (αν θυμάστε, από τη γραφή, η τελευταία πλήρως υποστηριζόμενη έκδοση ECMAScript είναι 5.1). Είναι σημαντικό να σημειωθεί, ωστόσο, ότι παρόλο που ο όρος «τάξη» εισάγεται στο JavaScript, εξακολουθεί να χρησιμοποιεί κληρονομιά βάσει πρωτοτύπου.
Ο προγραμματισμός που βασίζεται σε πρωτότυπα είναι ένα στυλ αντικειμενοστρεφούς προγραμματισμού στο οποίο η επαναχρησιμοποίηση συμπεριφοράς (γνωστή ως κληρονομιά) εκτελείται μέσω μιας διαδικασίας επαναχρησιμοποίησης υπαρχόντων αντικειμένων μέσω αντιπροσωπειών που χρησιμεύουν ως πρωτότυπα. Θα βρούμε περισσότερες λεπτομέρειες με αυτό μόλις φτάσουμε στην ενότητα σχεδιαστικών μοτίβων του άρθρου, καθώς αυτό το χαρακτηριστικό χρησιμοποιείται σε πολλά σχέδια σχεδίασης JavaScript.
Εάν έχετε εμπειρία με τη JavaScript, σίγουρα είστε εξοικειωμένοι με τον όρο συνάρτηση επανάκλησης . Για όσους δεν είναι εξοικειωμένοι με τον όρο, μια συνάρτηση επανάκλησης είναι μια συνάρτηση που αποστέλλεται ως παράμετρος (θυμηθείτε, το JavaScript αντιμετωπίζει τις λειτουργίες ως πολίτες πρώτης κατηγορίας) σε μια άλλη λειτουργία και εκτελείται μετά από ένα συμβάν ενεργοποιείται. Αυτό χρησιμοποιείται συνήθως για την εγγραφή σε συμβάντα όπως ένα κλικ του ποντικιού ή το πάτημα ενός κουμπιού πληκτρολογίου.
Κάθε φορά που ένα συμβάν, το οποίο έχει έναν ακροατή συνδεδεμένο σε αυτό, πυροδοτεί (διαφορετικά το συμβάν έχει χαθεί), ένα μήνυμα αποστέλλεται σε μια σειρά μηνυμάτων που υποβάλλονται σε σύγχρονη επεξεργασία, με τρόπο FIFO (first-in-first-out ). Αυτό ονομάζεται το βρόχος συμβάντος .
Κάθε ένα από τα μηνύματα στην ουρά έχει μια συνάρτηση που σχετίζεται με αυτό. Όταν ένα μήνυμα αποσυνδεθεί, ο χρόνος εκτέλεσης εκτελεί τη λειτουργία εντελώς πριν από την επεξεργασία οποιουδήποτε άλλου μηνύματος. Αυτό σημαίνει ότι, εάν μια συνάρτηση περιέχει άλλες κλήσεις λειτουργίας, όλες εκτελούνται πριν από την επεξεργασία ενός νέου μηνύματος από την ουρά. Αυτό ονομάζεται εκτέλεση έως ολοκλήρωση.
while (queue.waitForMessage()) { queue.processNextMessage(); }
Το queue.waitForMessage()
περιμένει συγχρόνως νέα μηνύματα. Κάθε ένα από τα μηνύματα που υποβάλλονται σε επεξεργασία έχει τη δική του στοίβα και υποβάλλεται σε επεξεργασία έως ότου η στοίβα είναι άδεια. Μόλις τελειώσει, ένα νέο μήνυμα υποβάλλεται σε επεξεργασία από την ουρά, εάν υπάρχει.
Ίσως έχετε επίσης ακούσει ότι η JavaScript δεν αποκλείει, πράγμα που σημαίνει ότι όταν εκτελείται μια ασύγχρονη λειτουργία, το πρόγραμμα μπορεί να επεξεργαστεί άλλα πράγματα, όπως η λήψη εισόδου χρήστη, ενώ περιμένει την ολοκλήρωση της ασύγχρονης λειτουργίας, χωρίς να εμποδίζει την κύρια νήμα εκτέλεσης. Αυτή είναι μια πολύ χρήσιμη ιδιότητα του JavaScript και ένα ολόκληρο άρθρο θα μπορούσε να γραφτεί μόνο σε αυτό το θέμα. Ωστόσο, δεν εμπίπτει στο πεδίο εφαρμογής αυτού του άρθρου.
Όπως είπα προηγουμένως, τα σχέδια σχεδίασης είναι επαναχρησιμοποιήσιμες λύσεις σε κοινά προβλήματα που σχετίζονται με τη σχεδίαση λογισμικού. Ας ρίξουμε μια ματιά σε μερικές από τις κατηγορίες σχεδίων σχεδιασμού.
Πώς δημιουργεί κανείς ένα μοτίβο; Ας υποθέσουμε ότι αναγνωρίσατε ένα κοινό πρόβλημα και έχετε τη δική σας μοναδική λύση σε αυτό το πρόβλημα, το οποίο δεν αναγνωρίζεται και δεν τεκμηριώνεται παγκοσμίως. Χρησιμοποιείτε αυτήν τη λύση κάθε φορά που αντιμετωπίζετε αυτό το πρόβλημα και πιστεύετε ότι είναι επαναχρησιμοποιήσιμο και ότι η κοινότητα προγραμματιστών θα μπορούσε να επωφεληθεί από αυτήν.
Γίνεται αμέσως μοτίβο; Ευτυχώς, όχι. Συχνά, μπορεί κανείς να έχει καλές πρακτικές σύνταξης κώδικα και απλά να κάνει λάθος κάτι που μοιάζει με μοτίβο για ένα όταν, στην πραγματικότητα, δεν είναι μοτίβο.
Πώς μπορείτε να ξέρετε πότε αυτό που νομίζετε ότι αναγνωρίζετε είναι στην πραγματικότητα ένα σχέδιο σχεδίασης;
Λαμβάνοντας τις απόψεις άλλων προγραμματιστών σχετικά με αυτό, γνωρίζοντας τη διαδικασία δημιουργίας ενός ίδιου μοτίβου και εξοικειωμένοι με τα υπάρχοντα μοτίβα. Υπάρχει μια φάση που πρέπει να περάσει ένα μοτίβο προτού γίνει πλήρες μοτίβο και αυτό ονομάζεται πρωτότυπο.
Ένα πρωτότυπο μοτίβο είναι ένα μοτίβο αν περνά μια συγκεκριμένη περίοδο δοκιμών από διάφορους προγραμματιστές και σενάρια όπου το μοτίβο αποδεικνύεται χρήσιμο και δίνει σωστά αποτελέσματα. Υπάρχει αρκετά μεγάλη δουλειά και τεκμηρίωση - τα περισσότερα από τα οποία δεν εμπίπτουν στο πεδίο εφαρμογής αυτού του άρθρου - που πρέπει να γίνουν προκειμένου να γίνει ένα ολοκληρωμένο μοτίβο αναγνωρισμένο από την κοινότητα.
Δεδομένου ότι ένα σχέδιο σχεδιασμού αντιπροσωπεύει την καλή πρακτική, ένα αντι-πρότυπο αντιπροσωπεύει την κακή πρακτική.
Ένα παράδειγμα ενός αντι-μοτίβου θα ήταν η τροποποίηση του Object
πρωτότυπο τάξης. Σχεδόν όλα τα αντικείμενα στο JavaScript κληρονομούνται από Object
(θυμηθείτε ότι η JavaScript χρησιμοποιεί κληρονομιά που βασίζεται σε πρωτότυπα), οπότε φανταστείτε ένα σενάριο όπου αλλάξατε αυτό το πρωτότυπο. Αλλαγές στο Object
πρωτότυπο θα μπορούσε να δει σε όλα τα αντικείμενα που κληρονομούν από αυτό το πρωτότυπο— που θα ήταν πλέον Αντικείμενα JavaScript . Αυτή είναι μια καταστροφή που περιμένει να συμβεί.
Ένα άλλο παράδειγμα, παρόμοιο με αυτό που αναφέρθηκε παραπάνω, είναι η τροποποίηση αντικειμένων που δεν σας ανήκουν. Ένα παράδειγμα αυτού θα ήταν η παράκαμψη μιας συνάρτησης από ένα αντικείμενο που χρησιμοποιείται σε πολλά σενάρια σε όλη την εφαρμογή. Εάν εργάζεστε με μια μεγάλη ομάδα, φανταστείτε τη σύγχυση που θα προκαλούσε. θα συναντούσατε γρήγορα συγκρούσεις ονομασίας, ασύμβατες υλοποιήσεις και εφιάλτες συντήρησης.
Παρόμοια με το πώς είναι χρήσιμο να γνωρίζετε για όλες τις καλές πρακτικές και λύσεις, είναι επίσης πολύ σημαντικό να γνωρίζετε και για τις κακές. Με αυτόν τον τρόπο, μπορείτε να τα αναγνωρίσετε και να αποφύγετε να κάνετε το λάθος μπροστά.
Τα μοτίβα σχεδιασμού μπορούν να κατηγοριοποιηθούν με πολλούς τρόπους, αλλά το πιο δημοφιλές είναι το ακόλουθο:
Αυτά τα μοτίβα ασχολούνται με μηχανισμούς δημιουργίας αντικειμένων που βελτιστοποιούν τη δημιουργία αντικειμένων σε σύγκριση με μια βασική προσέγγιση. Η βασική μορφή δημιουργίας αντικειμένων θα μπορούσε να οδηγήσει σε προβλήματα σχεδιασμού ή σε πρόσθετη πολυπλοκότητα στο σχεδιασμό. Τα δημιουργικά σχέδια σχεδίασης επιλύουν αυτό το πρόβλημα ελέγχοντας κατά κάποιο τρόπο τη δημιουργία αντικειμένων. Μερικά από τα δημοφιλή σχέδια σχεδίασης σε αυτήν την κατηγορία είναι:
Αυτά τα μοτίβα ασχολούνται με αντικειμενικές σχέσεις. Εξασφαλίζουν ότι εάν ένα μέρος του συστήματος αλλάξει, ολόκληρο το σύστημα δεν χρειάζεται να αλλάξει μαζί του. Τα πιο δημοφιλή μοτίβα αυτής της κατηγορίας είναι:
Αυτοί οι τύποι μοτίβων αναγνωρίζουν, εφαρμόζουν και βελτιώνουν την επικοινωνία μεταξύ διαφορετικών αντικειμένων σε ένα σύστημα. Συμβάλλουν στη διασφάλιση ότι τα διαφορετικά μέρη ενός συστήματος έχουν συγχρονισμένες πληροφορίες. Δημοφιλή παραδείγματα αυτών των προτύπων είναι:
Αυτοί οι τύποι σχεδίων σχεδίασης ασχολούνται με παραδείγματα προγραμματισμού πολλαπλών νημάτων. Μερικά από τα δημοφιλή είναι:
Σχέδια σχεδιασμού που χρησιμοποιούνται για αρχιτεκτονικούς σκοπούς. Μερικά από τα πιο διάσημα είναι:
Στην ακόλουθη ενότητα, θα ρίξουμε μια πιο προσεκτική ματιά σε μερικά από τα προαναφερθέντα σχέδια σχεδίασης με παραδείγματα που παρέχονται για καλύτερη κατανόηση.
Κάθε ένα από τα σχέδια σχεδίασης αντιπροσωπεύει έναν συγκεκριμένο τύπο λύσης σε έναν συγκεκριμένο τύπο προβλήματος. Δεν υπάρχει καθολικό σύνολο μοτίβων που να είναι πάντα η καλύτερη εφαρμογή. Πρέπει να μάθουμε πότε ένα συγκεκριμένο μοτίβο θα αποδειχθεί χρήσιμο και αν θα παρέχει πραγματική αξία. Μόλις εξοικειωθούμε με τα μοτίβα και τα σενάρια που ταιριάζουν καλύτερα, μπορούμε εύκολα να προσδιορίσουμε εάν ένα συγκεκριμένο μοτίβο είναι κατάλληλο για ένα συγκεκριμένο πρόβλημα.
Θυμηθείτε, η εφαρμογή του λανθασμένου μοτίβου σε ένα δεδομένο πρόβλημα θα μπορούσε να οδηγήσει σε ανεπιθύμητες ενέργειες όπως περιττή πολυπλοκότητα κώδικα, περιττή επιβάρυνση στην απόδοση ή ακόμη και την αναπαραγωγή ενός νέου αντι-μοτίβου.
Όλα αυτά είναι σημαντικά πράγματα που πρέπει να λάβετε υπόψη όταν σκεφτείτε να εφαρμόσετε ένα σχέδιο σχεδίασης στον κώδικα μας. Θα ρίξουμε μια ματιά σε μερικά από τα σχέδια σχεδίασης που θεωρούσα προσωπικά χρήσιμα και πιστεύω ότι κάθε ανώτερος προγραμματιστής JavaScript πρέπει να είναι εξοικειωμένος.
Όταν σκεφτόμαστε κλασικές αντικειμενοστρεφείς γλώσσες, ένας κατασκευαστής είναι μια ειδική λειτουργία σε μια τάξη που αρχικοποιεί ένα αντικείμενο με κάποιο σύνολο προεπιλεγμένων ή / και τιμών αποστολής.
Οι συνήθεις τρόποι δημιουργίας αντικειμένων σε JavaScript είναι οι τρεις ακόλουθοι τρόποι:
// either of the following ways can be used to create a new object var instance = {}; // or var instance = Object.create(Object.prototype); // or var instance = new Object();
Μετά τη δημιουργία ενός αντικειμένου, υπάρχουν τέσσερις τρόποι (από το ES3) για να προσθέσετε ιδιότητες σε αυτά τα αντικείμενα. Είναι τα εξής:
// supported since ES3 // the dot notation instance.key = 'A key's value'; // the square brackets notation instance['key'] = 'A key's value'; // supported since ES5 // setting a single property using Object.defineProperty Object.defineProperty(instance, 'key', { value: 'A key's value', writable: true, enumerable: true, configurable: true }); // setting multiple properties using Object.defineProperties Object.defineProperties(instance, { 'firstKey': { value: 'First key's value', writable: true }, 'secondKey': { value: 'Second key's value', writable: false } });
Ο πιο δημοφιλής τρόπος δημιουργίας αντικειμένων είναι οι σγουρές αγκύλες και, για την προσθήκη ιδιοτήτων, η σημείωση κουκίδων ή οι αγκύλες. Όποιος έχει οποιαδήποτε εμπειρία με το JavaScript το έχει χρησιμοποιήσει.
Αναφέραμε νωρίτερα ότι το JavaScript δεν υποστηρίζει εγγενείς τάξεις, αλλά υποστηρίζει κατασκευαστές μέσω της χρήσης μιας «νέας» λέξης-κλειδιού προθέματος σε μια κλήση συνάρτησης. Με αυτόν τον τρόπο, μπορούμε να χρησιμοποιήσουμε τη συνάρτηση ως κατασκευαστής και να προετοιμάσουμε τις ιδιότητές της με τον ίδιο τρόπο που θα κάναμε με έναν κλασικό κατασκευαστή γλωσσών.
// we define a constructor for Person objects function Person(name, age, isDeveloper) { this.name = name; this.age = age; this.isDeveloper = isDeveloper || false; this.writesCode = function() { console.log(this.isDeveloper? 'This person does write code' : 'This person does not write code'); } } // creates a Person instance with properties name: Bob, age: 38, isDeveloper: true and a method writesCode var person1 = new Person('Bob', 38, true); // creates a Person instance with properties name: Alice, age: 32, isDeveloper: false and a method writesCode var person2 = new Person('Alice', 32); // prints out: This person does write code person1.writesCode(); // prints out: this person does not write code person2.writesCode();
Ωστόσο, υπάρχει ακόμη περιθώριο βελτίωσης εδώ. Αν θα θυμάστε, ανέφερα προηγουμένως ότι η JavaScript χρησιμοποιεί κληρονομιά που βασίζεται σε πρωτότυπα. Το πρόβλημα με την προηγούμενη προσέγγιση είναι ότι η μέθοδος writesCode
επαναπροσδιορίζεται για καθεμία από τις παρουσίες του Person
κατασκευαστής. Μπορούμε να το αποφύγουμε αυτό θέτοντας τη μέθοδο στο πρωτότυπο της συνάρτησης:
// we define a constructor for Person objects function Person(name, age, isDeveloper) false; // we extend the function's prototype Person.prototype.writesCode = function() { console.log(this.isDeveloper? 'This person does write code' : 'This person does not write code'); } // creates a Person instance with properties name: Bob, age: 38, isDeveloper: true and a method writesCode var person1 = new Person('Bob', 38, true); // creates a Person instance with properties name: Alice, age: 32, isDeveloper: false and a method writesCode var person2 = new Person('Alice', 32); // prints out: This person does write code person1.writesCode(); // prints out: this person does not write code person2.writesCode();
Τώρα, και οι δύο παρουσίες του Person
ο κατασκευαστής μπορεί να έχει πρόσβαση σε μια κοινή παρουσία του writesCode()
μέθοδος.
Όσον αφορά τις ιδιαιτερότητες, η JavaScript δεν σταματά ποτέ να εκπλήσσει. Ένα άλλο ιδιαίτερο πράγμα στη JavaScript (τουλάχιστον όσον αφορά τις γλώσσες που είναι αντικειμενοστραφείς) είναι ότι το JavaScript δεν υποστηρίζει τροποποιητές πρόσβασης. Σε μια κλασική γλώσσα OOP, ένας χρήστης ορίζει μια τάξη και καθορίζει τα δικαιώματα πρόσβασης για τα μέλη της. Δεδομένου ότι το JavaScript στην απλή του μορφή δεν υποστηρίζει ούτε τάξεις ούτε τροποποιητές πρόσβασης, οι προγραμματιστές JavaScript βρήκαν έναν τρόπο να μιμούνται αυτήν τη συμπεριφορά όταν χρειάζεται.
Πριν προχωρήσουμε στις λεπτομέρειες μοτίβου της ενότητας, ας μιλήσουμε για την έννοια του κλεισίματος. ΕΝΑ κλείσιμο είναι μια συνάρτηση με πρόσβαση στο γονικό πεδίο εφαρμογής, ακόμη και μετά τη λήξη της γονικής συνάρτησης. Μας βοηθούν να μιμηθούμε τη συμπεριφορά των τροποποιητών πρόσβασης μέσω του scoping. Ας το δείξουμε μέσω ενός παραδείγματος:
// we used an immediately invoked function expression // to create a private variable, counter var counterIncrementer = (function() { var counter = 0; return function() { return ++counter; }; })(); // prints out 1 console.log(counterIncrementer()); // prints out 2 console.log(counterIncrementer()); // prints out 3 console.log(counterIncrementer());
Όπως μπορείτε να δείτε, χρησιμοποιώντας το IIFE, έχουμε συνδέσει τη μεταβλητή μετρητή σε μια συνάρτηση που κλήθηκε και έκλεισε, αλλά εξακολουθεί να είναι προσβάσιμη από τη θυγατρική συνάρτηση που την αυξάνει. Δεδομένου ότι δεν μπορούμε να αποκτήσουμε πρόσβαση στη μεταβλητή μετρητή από το εξωτερικό της έκφρασης της συνάρτησης, το κάναμε ιδιωτικό μέσω χειρισμών scoping.
Χρησιμοποιώντας τα πώματα, μπορούμε να δημιουργήσουμε αντικείμενα με ιδιωτικά και δημόσια ανταλλακτικά. Αυτά ονομάζονται ενότητες και είναι πολύ χρήσιμα όποτε θέλουμε να αποκρύψουμε ορισμένα μέρη ενός αντικειμένου και να εκθέσουμε μόνο μια διεπαφή στον χρήστη της λειτουργικής μονάδας. Ας το δείξουμε σε ένα παράδειγμα:
// through the use of a closure we expose an object // as a public API which manages the private objects array var collection = (function() { // private members var objects = []; // public members return { addObject: function(object) { objects.push(object); }, removeObject: function(object) { var index = objects.indexOf(object); if (index >= 0) { objects.splice(index, 1); } }, getObjects: function() { return JSON.parse(JSON.stringify(objects)); } }; })(); collection.addObject('Bob'); collection.addObject('Alice'); collection.addObject('Franck'); // prints ['Bob', 'Alice', 'Franck'] console.log(collection.getObjects()); collection.removeObject('Alice'); // prints ['Bob', 'Franck'] console.log(collection.getObjects());
Το πιο χρήσιμο πράγμα που εισάγει αυτό το μοτίβο είναι ο σαφής διαχωρισμός ιδιωτικών και δημόσιων τμημάτων ενός αντικειμένου, η οποία είναι μια ιδέα πολύ παρόμοια με τους προγραμματιστές που προέρχονται από ένα κλασικό αντικειμενοστρεφό υπόβαθρο.
Ωστόσο, δεν είναι όλα τέλεια. Όταν επιθυμείτε να αλλάξετε την ορατότητα ενός μέλους, πρέπει να τροποποιήσετε τον κωδικό οπουδήποτε έχετε χρησιμοποιήσει αυτό το μέλος λόγω της διαφορετικής φύσης της πρόσβασης σε δημόσια και ιδιωτικά μέρη. Επίσης, οι μέθοδοι που προστέθηκαν στο αντικείμενο μετά τη δημιουργία τους δεν έχουν πρόσβαση στα ιδιωτικά μέλη του αντικειμένου.
Αυτό το μοτίβο είναι μια βελτίωση που έγινε στο μοτίβο της ενότητας όπως απεικονίζεται παραπάνω. Η κύρια διαφορά είναι ότι γράφουμε ολόκληρη τη λογική αντικειμένων στο ιδιωτικό πεδίο εφαρμογής της ενότητας και στη συνέχεια απλώς εκθέτουμε τα μέρη που θέλουμε να είμαστε δημόσια επιστρέφοντας ένα ανώνυμο αντικείμενο. Μπορούμε επίσης να αλλάξουμε την ονομασία ιδιωτικών μελών κατά τη χαρτογράφηση ιδιωτικών μελών στα αντίστοιχα δημόσια μέλη τους.
// we write the entire object logic as private members and // expose an anonymous object which maps members we wish to reveal // to their corresponding public members var namesCollection = (function() { // private members var objects = []; function addObject(object) { objects.push(object); } function removeObject(object) { var index = objects.indexOf(object); if (index >= 0) { objects.splice(index, 1); } } function getObjects() { return JSON.parse(JSON.stringify(objects)); } // public members return { addName: addObject, removeName: removeObject, getNames: getObjects }; })(); namesCollection.addName('Bob'); namesCollection.addName('Alice'); namesCollection.addName('Franck'); // prints ['Bob', 'Alice', 'Franck'] console.log(namesCollection.getNames()); namesCollection.removeName('Alice'); // prints ['Bob', 'Franck'] console.log(namesCollection.getNames());
Το αποκαλυπτικό μοτίβο λειτουργικής μονάδας είναι ένας από τουλάχιστον τρεις τρόπους με τους οποίους μπορούμε να εφαρμόσουμε ένα μοτίβο λειτουργικής μονάδας. Οι διαφορές μεταξύ του αποκαλυπτικού μοτίβου λειτουργικής μονάδας και των άλλων παραλλαγών του μοτίβου λειτουργικής μονάδας είναι κυρίως στον τρόπο με τον οποίο αναφέρονται τα δημόσια μέλη. Ως αποτέλεσμα, το αποκαλυπτικό μοτίβο λειτουργικής μονάδας είναι πολύ πιο εύκολο στη χρήση και τροποποίηση. Ωστόσο, μπορεί να αποδειχθεί εύθραυστο σε ορισμένα σενάρια, όπως η χρήση αντικειμένων RMP ως πρωτότυπων σε μια αλυσίδα κληρονομιάς. Οι προβληματικές καταστάσεις είναι οι εξής:
Το μοτίβο singleton χρησιμοποιείται σε σενάρια όταν χρειαζόμαστε ακριβώς μια παρουσία μιας τάξης. Για παράδειγμα, πρέπει να έχουμε ένα αντικείμενο που περιέχει κάποια διαμόρφωση για κάτι. Σε αυτές τις περιπτώσεις, δεν είναι απαραίτητο να δημιουργήσετε ένα νέο αντικείμενο όποτε το αντικείμενο διαμόρφωσης απαιτείται κάπου στο σύστημα.
var singleton = (function() { // private singleton value which gets initialized only once var config; function initializeConfiguration(values){ this.randomNumber = Math.random(); values = values || {}; this.number = values.number || 5; this.size = values.size || 10; } // we export the centralized method for retrieving the singleton value return { getConfig: function(values) { // we initialize the singleton value only once if (config === undefined) { config = new initializeConfiguration(values); } // and return the same config value wherever it is asked for return config; } }; })(); var configObject = singleton.getConfig({ 'size': 8 }); // prints number: 5, size: 8, randomNumber: someRandomDecimalValue console.log(configObject); var configObject1 = singleton.getConfig({ 'number': 8 }); // prints number: 5, size: 8, randomNumber: same randomDecimalValue as in first config console.log(configObject1);
Όπως μπορείτε να δείτε στο παράδειγμα, ο τυχαίος αριθμός που δημιουργείται είναι πάντα ο ίδιος, καθώς και οι τιμές διαμόρφωσης που αποστέλλονται.
Είναι σημαντικό να σημειωθεί ότι το σημείο πρόσβασης για την ανάκτηση της τιμής singleton πρέπει να είναι μόνο ένα και πολύ γνωστό. Ένα μειονέκτημα για τη χρήση αυτού του μοτίβου είναι ότι είναι μάλλον δύσκολο να ελεγχθεί.
Το μοτίβο του παρατηρητή είναι ένα πολύ χρήσιμο εργαλείο όταν έχουμε ένα σενάριο όπου πρέπει να βελτιώσουμε την επικοινωνία μεταξύ διαφορετικών τμημάτων του συστήματός μας με βελτιστοποιημένο τρόπο. Προωθεί τη χαλαρή σύνδεση μεταξύ αντικειμένων.
Υπάρχουν διάφορες εκδόσεις αυτού του μοτίβου, αλλά στην πιο βασική του μορφή, έχουμε δύο κύρια μέρη του μοτίβου. Το πρώτο είναι θέμα και το δεύτερο είναι παρατηρητές.
Ένα θέμα χειρίζεται όλες τις λειτουργίες σχετικά με ένα συγκεκριμένο θέμα στο οποίο οι παρατηρητές εγγραφούν. Αυτές οι λειτουργίες εγγράφουν έναν παρατηρητή σε ένα συγκεκριμένο θέμα, καταργούν την εγγραφή ενός παρατηρητή από ένα συγκεκριμένο θέμα και ειδοποιούν τους παρατηρητές για ένα συγκεκριμένο θέμα κατά τη δημοσίευση ενός συμβάντος.
Ωστόσο, υπάρχει μια παραλλαγή αυτού του μοτίβου που ονομάζεται μοτίβο εκδότη / συνδρομητή, το οποίο θα χρησιμοποιήσω ως παράδειγμα σε αυτήν την ενότητα. Η κύρια διαφορά μεταξύ ενός κλασικού μοτίβου παρατηρητή και του προτύπου εκδότη / συνδρομητή είναι ότι ο εκδότης / συνδρομητής προωθεί ακόμη πιο χαλαρή σύζευξη από ότι το μοτίβο παρατηρητή.
Στο μοτίβο του παρατηρητή, το θέμα κρατά τις αναφορές στους εγγεγραμμένους παρατηρητές και τις μεθόδους κλήσεων απευθείας από τα ίδια τα αντικείμενα, ενώ, στο μοτίβο εκδότη / συνδρομητή, έχουμε κανάλια, τα οποία χρησιμεύουν ως γέφυρα επικοινωνίας μεταξύ ενός συνδρομητή και ενός εκδότη. Ο εκδότης ενεργοποιεί ένα συμβάν και εκτελεί απλώς τη συνάρτηση επιστροφής που αποστέλλεται για αυτό το συμβάν.
Θα παρουσιάσω ένα σύντομο παράδειγμα του μοτίβου εκδότη / συνδρομητή, αλλά για όσους ενδιαφέρονται, ένα κλασικό παράδειγμα μοτίβου παρατηρητή μπορεί εύκολα να βρεθεί στο διαδίκτυο.
var publisherSubscriber = {}; // we send in a container object which will handle the subscriptions and publishings (function(container) { // the id represents a unique subscription id to a topic var id = 0; // we subscribe to a specific topic by sending in // a callback function to be executed on event firing container.subscribe = function(topic, f) { if (!(topic in container)) { container[topic] = []; } container[topic].push({ 'id': ++id, 'callback': f }); return id; } // each subscription has its own unique ID, which we use // to remove a subscriber from a certain topic container.unsubscribe = function(topic, id) { var subscribers = []; for (var subscriber of container[topic]) { if (subscriber.id !== id) { subscribers.push(subscriber); } } container[topic] = subscribers; } container.publish = function(topic, data) { for (var subscriber of container[topic]) { // when executing a callback, it is usually helpful to read // the documentation to know which arguments will be // passed to our callbacks by the object firing the event subscriber.callback(data); } } })(publisherSubscriber); var subscriptionID1 = publisherSubscriber.subscribe('mouseClicked', function(data) { console.log('I am Bob's callback function for a mouse clicked event and this is my event data: ' + JSON.stringify(data)); }); var subscriptionID2 = publisherSubscriber.subscribe('mouseHovered', function(data) { console.log('I am Bob's callback function for a hovered mouse event and this is my event data: ' + JSON.stringify(data)); }); var subscriptionID3 = publisherSubscriber.subscribe('mouseClicked', function(data) { console.log('I am Alice's callback function for a mouse clicked event and this is my event data: ' + JSON.stringify(data)); }); // NOTE: after publishing an event with its data, all of the // subscribed callbacks will execute and will receive // a data object from the object firing the event // there are 3 console.logs executed publisherSubscriber.publish('mouseClicked', {'data': 'data1'}); publisherSubscriber.publish('mouseHovered', {'data': 'data2'}); // we unsubscribe from an event by removing the subscription ID publisherSubscriber.unsubscribe('mouseClicked', subscriptionID3); // there are 2 console.logs executed publisherSubscriber.publish('mouseClicked', {'data': 'data1'}); publisherSubscriber.publish('mouseHovered', {'data': 'data2'});
Αυτό το μοτίβο σχεδίασης είναι χρήσιμο σε περιπτώσεις όπου πρέπει να εκτελέσουμε πολλαπλές λειτουργίες σε ένα μόνο συμβάν που ενεργοποιείται. Φανταστείτε ότι έχετε ένα σενάριο όπου πρέπει να πραγματοποιήσουμε πολλές κλήσεις AJAX σε μια υπηρεσία back-end και στη συνέχεια να εκτελέσετε άλλες κλήσεις AJAX ανάλογα με το αποτέλεσμα. Θα πρέπει να τοποθετήσετε τις κλήσεις AJAX το ένα μέσα στο άλλο, πιθανόν να εισέλθουν σε μια κατάσταση γνωστή ως callback hell. Η χρήση του προτύπου εκδότη / συνδρομητή είναι μια πολύ πιο κομψή λύση.
Ένα μειονέκτημα για τη χρήση αυτού του μοτίβου είναι ο δύσκολος έλεγχος διαφόρων τμημάτων του συστήματός μας. Δεν υπάρχει κομψός τρόπος για να γνωρίζουμε εάν τα συνδρομητικά μέρη του συστήματος συμπεριφέρονται ή όχι.
Θα καλύψουμε εν συντομία ένα μοτίβο που είναι επίσης πολύ χρήσιμο όταν μιλάμε για αποσυνδεδεμένα συστήματα. Όταν έχουμε ένα σενάριο όπου πολλά μέρη ενός συστήματος πρέπει να επικοινωνούν και να συντονίζονται, ίσως μια καλή λύση θα ήταν να εισαγάγουμε έναν μεσολαβητή.
Ένας διαμεσολαβητής είναι ένα αντικείμενο που χρησιμοποιείται ως κεντρικό σημείο επικοινωνίας μεταξύ διαφορετικών τμημάτων ενός συστήματος και χειρίζεται τη ροή εργασίας μεταξύ τους. Τώρα, είναι σημαντικό να τονιστεί ότι χειρίζεται τη ροή εργασίας. Γιατί είναι σημαντικό?
Επειδή υπάρχει μεγάλη ομοιότητα με το μοτίβο εκδότη / συνδρομητή. Μπορείτε να ρωτήσετε τον εαυτό σας, Εντάξει, οπότε αυτά τα δύο μοτίβα βοηθούν στην καλύτερη επικοινωνία μεταξύ αντικειμένων… Ποια είναι η διαφορά;
Η διαφορά είναι ότι ένας διαμεσολαβητής χειρίζεται τη ροή εργασίας, ενώ ο εκδότης / συνδρομητής χρησιμοποιεί κάτι που ονομάζεται τύπος επικοινωνίας «φωτιά και ξεχάστε». Ο εκδότης / συνδρομητής είναι απλώς ένα πρόγραμμα συγκέντρωσης συμβάντων, που σημαίνει ότι φροντίζει απλώς να ενεργοποιήσει τα συμβάντα και να ενημερώσει τους σωστούς συνδρομητές ποια συμβάντα ενεργοποιήθηκαν. Ο συγκεντρωτής συμβάντων δεν ενδιαφέρεται για το τι θα συμβεί μετά την ενεργοποίηση ενός συμβάντος, κάτι που δεν συμβαίνει με έναν διαμεσολαβητή.
Ένα ωραίο παράδειγμα ενός διαμεσολαβητή είναι ένας τύπος διεπαφής μάγου. Ας υποθέσουμε ότι έχετε μια μεγάλη διαδικασία εγγραφής για ένα σύστημα στο οποίο έχετε εργαστεί. Συχνά, όταν απαιτούνται πολλές πληροφορίες από έναν χρήστη, είναι καλή πρακτική να το χωρίζετε σε πολλά βήματα.
Με αυτόν τον τρόπο, ο κωδικός θα είναι πολύ καθαρότερος (ευκολότερος στη συντήρηση) και ο χρήστης δεν θα κατακλύζεται από τον όγκο των πληροφοριών που ζητούνται μόνο για να ολοκληρωθεί η εγγραφή. Ένας διαμεσολαβητής είναι ένα αντικείμενο που θα χειριζόταν τα βήματα εγγραφής, λαμβάνοντας υπόψη διαφορετικές πιθανές ροές εργασίας που θα μπορούσαν να συμβούν λόγω του γεγονότος ότι κάθε χρήστης θα μπορούσε ενδεχομένως να έχει μια μοναδική διαδικασία εγγραφής.
Το προφανές όφελος από αυτό το σχέδιο σχεδίασης είναι η βελτιωμένη επικοινωνία μεταξύ διαφορετικών τμημάτων ενός συστήματος, τα οποία τώρα επικοινωνούν μέσω του διαμεσολαβητή και της καθαρότερης βάσης κώδικα.
Ένα μειονέκτημα θα ήταν ότι τώρα έχουμε εισαγάγει ένα μόνο σημείο αποτυχίας στο σύστημά μας, που σημαίνει ότι εάν ο μεσολαβητής μας αποτύχει, ολόκληρο το σύστημα θα μπορούσε να σταματήσει να λειτουργεί.
Όπως έχουμε ήδη αναφέρει σε ολόκληρο το άρθρο, το JavaScript δεν υποστηρίζει μαθήματα στη μητρική του μορφή. Η κληρονομικότητα μεταξύ των αντικειμένων πραγματοποιείται χρησιμοποιώντας προγραμματισμό που βασίζεται σε πρωτότυπα.
Μας επιτρέπει να δημιουργήσουμε αντικείμενα που μπορούν να χρησιμεύσουν ως πρωτότυπο για άλλα αντικείμενα που δημιουργούνται. Το πρωτότυπο αντικείμενο χρησιμοποιείται ως σχέδιο για κάθε αντικείμενο που δημιουργεί ο κατασκευαστής.
Όπως έχουμε ήδη μιλήσει για αυτό στις προηγούμενες ενότητες, ας δείξουμε ένα απλό παράδειγμα για το πώς μπορεί να χρησιμοποιηθεί αυτό το μοτίβο.
var personPrototype = { sayHi: function() { console.log('Hello, my name is ' + this.name + ', and I am ' + this.age); }, sayBye: function() { console.log('Bye Bye!'); } }; function Person(name, age) { name = name || 'John Doe'; age = age || 26; function constructorFunction(name, age) { this.name = name; this.age = age; }; constructorFunction.prototype = personPrototype; var instance = new constructorFunction(name, age); return instance; } var person1 = Person(); var person2 = Person('Bob', 38); // prints out Hello, my name is John Doe, and I am 26 person1.sayHi(); // prints out Hello, my name is Bob, and I am 38 person2.sayHi();
Παρατηρήστε πώς η κληρονομιά του πρωτοτύπου ενισχύει επίσης την απόδοση, καθώς και τα δύο αντικείμενα περιέχουν αναφορά στις συναρτήσεις που εφαρμόζονται στο ίδιο το πρωτότυπο, αντί σε καθένα από τα αντικείμενα.
Το μοτίβο εντολών είναι χρήσιμο σε περιπτώσεις που θέλουμε να αποσυνδέσουμε αντικείμενα που εκτελούν τις εντολές από αντικείμενα που εκδίδουν τις εντολές. Για παράδειγμα, φανταστείτε ένα σενάριο όπου η εφαρμογή μας χρησιμοποιεί μεγάλο αριθμό κλήσεων υπηρεσίας API. Στη συνέχεια, ας πούμε ότι οι υπηρεσίες API αλλάζουν. Θα πρέπει να τροποποιήσουμε τον κώδικα όπου κληθούν τα API που άλλαξαν.
Αυτό θα ήταν ένα εξαιρετικό μέρος για να εφαρμόσετε ένα επίπεδο αφαίρεσης, το οποίο θα διαχωρίζει τα αντικείμενα που καλούν μια υπηρεσία API από τα αντικείμενα που τους λένε πότε για να καλέσετε την υπηρεσία API. Με αυτόν τον τρόπο, αποφεύγουμε την τροποποίηση σε όλα τα μέρη όπου έχουμε ανάγκη να καλέσουμε την υπηρεσία, αλλά μάλλον πρέπει να αλλάξουμε μόνο τα αντικείμενα που πραγματοποιούν την ίδια την κλήση, που είναι μόνο ένα μέρος.
Όπως και με οποιοδήποτε άλλο μοτίβο, πρέπει να γνωρίζουμε πότε ακριβώς υπάρχει πραγματική ανάγκη για ένα τέτοιο μοτίβο. Πρέπει να έχουμε επίγνωση της ανταλλαγής που κάνουμε, καθώς προσθέτουμε ένα επιπλέον επίπεδο αφαίρεσης στις κλήσεις API, το οποίο θα μειώσει την απόδοση, αλλά ενδεχομένως θα εξοικονομήσει πολύ χρόνο όταν πρέπει να τροποποιήσουμε αντικείμενα που εκτελούν τις εντολές.
// the object which knows how to execute the command var invoker = { add: function(x, y) { return x + y; }, subtract: function(x, y) { return x - y; } } // the object which is used as an abstraction layer when // executing commands; it represents an interface // toward the invoker object var manager = { execute: function(name, args) { if (name in invoker) { return invoker[name].apply(invoker, [].slice.call(arguments, 1)); } return false; } } // prints 8 console.log(manager.execute('add', 3, 5)); // prints 2 console.log(manager.execute('subtract', 5, 3));
Το μοτίβο πρόσοψης χρησιμοποιείται όταν θέλουμε να δημιουργήσουμε ένα επίπεδο αφαίρεσης ανάμεσα σε αυτό που εμφανίζεται δημόσια και σε αυτό που εφαρμόζεται πίσω από την κουρτίνα. Χρησιμοποιείται όταν επιθυμείται μια ευκολότερη ή απλούστερη διεπαφή σε ένα υποκείμενο αντικείμενο.
Ένα εξαιρετικό παράδειγμα αυτού του μοτίβου θα ήταν οι επιλογείς από βιβλιοθήκες χειρισμού DOM όπως το jQuery, το Dojo ή το D3. Ίσως έχετε παρατηρήσει τη χρήση αυτών των βιβλιοθηκών ότι έχουν πολύ ισχυρές δυνατότητες επιλογής. μπορείτε να γράψετε σε σύνθετα ερωτήματα όπως:
jQuery('.parent .child div.span')
Απλοποιεί πολύ τις δυνατότητες επιλογής, και παρόλο που φαίνεται απλό στην επιφάνεια, υπάρχει μια ολόκληρη σύνθετη λογική που εφαρμόζεται κάτω από την κουκούλα για να λειτουργήσει αυτό.
Πρέπει επίσης να γνωρίζουμε την απόδοση-απλότητα απόδοσης. Είναι επιθυμητό να αποφευχθεί η υπερβολική πολυπλοκότητα εάν δεν είναι αρκετά ωφέλιμο. Στην περίπτωση των προαναφερθεισών βιβλιοθηκών, η ανταλλαγή αξίζει τον κόπο, καθώς είναι όλες πολύ επιτυχημένες βιβλιοθήκες.
Τα σχέδια σχεδίασης είναι ένα πολύ χρήσιμο εργαλείο το οποίο οποιοδήποτε ανώτερος προγραμματιστής JavaScript πρέπει να γνωρίζετε. Η γνώση των λεπτομερειών σχετικά με τα σχέδια σχεδίασης θα μπορούσε να αποδειχθεί εξαιρετικά χρήσιμη και να σας εξοικονομήσει πολύ χρόνο στον κύκλο ζωής οποιουδήποτε έργου, ειδικά στο τμήμα συντήρησης. Η τροποποίηση και η συντήρηση συστημάτων γραμμένων με τη βοήθεια σχεδίων σχεδιασμού που ταιριάζουν στις ανάγκες του συστήματος θα μπορούσαν να αποδειχθούν πολύτιμα.
Για να διατηρήσουμε το άρθρο σχετικά σύντομο, δεν θα εμφανίζουμε άλλα παραδείγματα. Για όσους ενδιαφέρονται, μια μεγάλη έμπνευση για αυτό το άρθρο προήλθε από το βιβλίο των συμμοριών των τεσσάρων Σχέδια σχεδίασης: Στοιχεία επαναχρησιμοποιήσιμου αντικειμενοστραφούς λογισμικού και του Addy Osmani Εκμάθηση μοτίβων σχεδίασης JavaScript . Συνιστώ ανεπιφύλακτα και τα δύο βιβλία.
Σχετίζεται με: Ως προγραμματιστής JS, αυτό είναι που με κρατάει τη νύχτα / Κάνοντας την αίσθηση της σύγχυσης ES6 ClassΤο JavaScript είναι ασύγχρονο, υποστηρίζει λειτουργίες πρώτης κατηγορίας και βασίζεται σε πρωτότυπα.
Τα μοτίβα σχεδιασμού είναι επαναχρησιμοποιήσιμες λύσεις σε προβλήματα που εμφανίζονται συνήθως στη σχεδίαση λογισμικού. Είναι αποδεδειγμένες λύσεις, εύκολα επαναχρησιμοποιήσιμες και εκφραστικές. Μειώνουν το μέγεθος της βάσης κωδικών σας, αποτρέπουν τη μελλοντική αναδιαμόρφωση και διευκολύνουν την κατανόησή του από άλλους προγραμματιστές.
Το JavaScript είναι μια γλώσσα scripting από την πλευρά του πελάτη για προγράμματα περιήγησης που δημιουργήθηκε για πρώτη φορά από τον Brendan Eich για το Netscape Navigator από αυτό που είναι τώρα το Mozilla.
Το ECMAScript είναι μια τυποποιημένη προδιαγραφή γλώσσας scripting την οποία όλα τα σύγχρονα προγράμματα περιήγησης προσπαθούν να υποστηρίξουν. Υπάρχουν πολλές εφαρμογές του ECMAScript, το πιο δημοφιλές από τα οποία είναι το JavaScript.
Ένα πρωτότυπο μοτίβο είναι ένα μοτίβο-αν είναι εάν περάσει μια συγκεκριμένη περίοδο δοκιμών από διάφορους προγραμματιστές και σενάρια όπου το μοτίβο αποδεικνύεται χρήσιμο και δίνει σωστά αποτελέσματα.
Εάν ένα σχέδιο σχεδίασης αντιπροσωπεύει την καλή πρακτική, τότε ένα αντι-σχέδιο αντιπροσωπεύει την κακή πρακτική. Ένα παράδειγμα αντι-μοτίβου θα ήταν η τροποποίηση του πρωτοτύπου κλάσης αντικειμένων. Αλλαγές στο πρωτότυπο αντικειμένου είναι ορατές σε όλα τα αντικείμενα που κληρονομούν από αυτό το πρωτότυπο (δηλαδή, σχεδόν όλα τα αντικείμενα σε JavaScript).
Τα σχέδια σχεδιασμού μπορεί να είναι δημιουργικά, δομικά, συμπεριφορικά, ταυτόχρονα ή αρχιτεκτονικά.
Μερικά παραδείγματα που συζητήθηκαν στο παραπάνω άρθρο περιλαμβάνουν το μοτίβο κατασκευαστή, το μοτίβο δομοστοιχείου, το μοτίβο αποκαλυπτικής μονάδας, το μοτίβο μονόκλωνου, το μοτίβο παρατηρητή, το μοτίβο μεσολαβητή, το πρότυπο πρωτοτύπου, το μοτίβο εντολών και το μοτίβο πρόσοψης.