Προγραμματισμός

Πάρα πολλές παράμετροι στις μεθόδους Java, Μέρος 6: Επιστρέφει η μέθοδος

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

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

Ο μηχανισμός χειρισμού εξαιρέσεων της Java είναι επίσης μια άλλη προσέγγιση για τη διατήρηση ενός "αποτελέσματος" μιας μεθόδου στους καλούντες. Οι ελεγμένες εξαιρέσεις, ειδικότερα, διαφημίζονται στον καλούντα μέσω της ρήτρας ρίψεων. Στην πραγματικότητα, ο Jim Waldo, στο βιβλίο του Java: The Good Parts, δηλώνει ότι είναι ευκολότερο να κατανοήσουμε τις εξαιρέσεις Java όταν κάποιος σκέφτεται ότι οι εξαιρέσεις Java ως άλλος τύπος μεθόδου επιστρέφουν περιοριζόμενοι στο να είναι ένας Throwable τύπος.

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

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

Υπάρχουν ορισμένα μειονεκτήματα από την επιστροφή της κατάστασης στις κλήσεις μέσω των παρεχόμενων παραμέτρων. Αυτή η προσέγγιση συχνά παραβιάζει την αρχή της ελάχιστης έκπληξης, καθώς οι περισσότεροι προγραμματιστές Java αναμένουν πιθανώς ότι οι παράμετροι θα είναι ΕΙΣΑΓΩΓΕΣ και όχι ΕΞΟΔΟΣ (και η Java δεν παρέχει υποστήριξη κώδικα για να καθορίσει τη διαφορά). Ο Μπομπ Μάρτιν το θέτει έτσι στο βιβλίο του Clean Code, "Γενικά, τα επιχειρήματα εξόδου πρέπει να αποφεύγονται." Ένα άλλο μειονέκτημα της χρήσης ορισμάτων ως μέσου για μια μέθοδο για την παροχή κατάστασης ή εξόδου στον καλούντα είναι ότι αυτό αυξάνει την ακαταστασία των ορισμάτων που μεταβιβάζονται σε μια μέθοδο. Έχοντας αυτό κατά νου, το υπόλοιπο αυτής της ανάρτησης επικεντρώνεται σε εναλλακτικές λύσεις για την επιστροφή πολλαπλών τιμών μέσω παραμέτρων μεταβίβασης.

Αν και οι μέθοδοι Java μπορούν να επιστρέψουν μόνο ένα αντικείμενο ή ένα πρωτόγονο, αυτό δεν είναι πραγματικά περιορισμός όταν κάποιος θεωρεί ότι ένα αντικείμενο μπορεί να είναι οτιδήποτε θέλουμε να είναι. Υπάρχουν πολλές προσεγγίσεις που έχω δει αλλά δεν προτείνω. Ένα από αυτά επιστρέφει έναν πίνακα ή μια συλλογή παρουσιών αντικειμένου με καθεμία Αντικείμενο είναι ένα ανόμοιο και διακριτό και συχνά άσχετο «πράγμα». Για παράδειγμα, η μέθοδος μπορεί να επιστρέψει τρεις τιμές ως τρία στοιχεία ενός πίνακα ή συλλογής. Μια παραλλαγή αυτής της προσέγγισης είναι να χρησιμοποιήσετε μια πλειάδα ζεύγους ή μια πλειάδα μεγέθους n για να επιστρέψετε πολλές σχετικές τιμές. Μια άλλη παραλλαγή σε αυτήν την προσέγγιση είναι να επιστρέψετε έναν χάρτη Java που χαρτογραφεί αυθαίρετα κλειδιά στη σχετική τιμή τους. Όπως και με τις άλλες λύσεις, αυτή η προσέγγιση επιβαρύνει τον πελάτη για να γνωρίζει τι είναι αυτά τα κλειδιά και να έχει πρόσβαση στις τιμές του χάρτη μέσω αυτών των κλειδιών.

Η επόμενη λίστα κωδικών περιέχει πολλές από αυτές τις λιγότερο ελκυστικές προσεγγίσεις για την επιστροφή πολλαπλών τιμών χωρίς παραβίαση των παραμέτρων μεθόδου για την επιστροφή πολλαπλών τιμών.

Επιστροφή πολλαπλών τιμών μέσω γενικών δομών δεδομένων

 // ================================================ =============== // ΣΗΜΕΙΩΣΗ: Αυτά τα παραδείγματα προορίζονται αποκλειστικά για την απεικόνιση ενός σημείου // και ΔΕΝ συνιστώνται για τον κωδικό παραγωγής. // ================================================ =============== / ** * Παρέχετε πληροφορίες ταινίας. * * @return Πληροφορίες ταινίας σε μορφή πίνακα όπου οι λεπτομέρειες αντιστοιχίζονται σε * στοιχεία με τα ακόλουθα ευρετήρια στον πίνακα: * 0: Τίτλος ταινίας * 1: Έτος κυκλοφορίας * 2: Σκηνοθέτης * 3: Βαθμολογία * / δημόσιο αντικείμενο [] getMovieInformation () {final Object [] movieDetails = {"World War Z", 2013, "Marc Forster", "PG-13"}; επιστροφή ταινίαDetails? } / ** * Παρέχετε πληροφορίες ταινίας. * * @return Πληροφορίες ταινίας με τη μορφή λίστας όπου παρέχονται λεπτομέρειες * με αυτήν τη σειρά: Τίτλος ταινίας, Έτος κυκλοφορίας, Σκηνοθέτης, Βαθμολογία. * / δημόσια Λίστα getMovieDetails () {return Arrays.asList ("Ender's Game", 2013, "Gavin Hood", "PG-13"); } / ** * Παρέχετε πληροφορίες ταινίας. * * @return Πληροφορίες ταινίας σε μορφή χάρτη. Τα χαρακτηριστικά της ταινίας μπορούν * να αποκτηθούν αναζητώντας στον χάρτη αυτά τα βασικά στοιχεία: "Τίτλος", "Έτος", * "Σκηνοθέτης" και "Βαθμολογία" ./ * / δημόσιο Χάρτης getMovieDetailsMap () {τελικό HashMap map = νέο HashMap (); map.put ("Τίτλος", "Despicable Me 2"); map.put ("Έτος", 2013); map.put ("Σκηνοθέτης", "Pierre Coffin και Chris Renaud") · map.put ("Αξιολόγηση", "PG"); επιστροφή χάρτη; } 

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

Προτιμώ να γράφω προσαρμοσμένα αντικείμενα για τις επιστροφές μου όταν πρέπει να επιστρέψω περισσότερες από μία τιμές. Είναι λίγο περισσότερη δουλειά από τη χρήση μιας διάταξης, συλλογής ή δομής πλειάδας, αλλά η πολύ μικρή ποσότητα επιπλέον εργασίας (συνήθως λίγα λεπτά με σύγχρονα IDE Java) αποδίδει με ευανάγνωστη και ευχέρεια που δεν είναι διαθέσιμη με αυτές τις πιο γενικές προσεγγίσεις. Αντί να χρειάζεται να εξηγήσω με τον Javadoc ή να ζητήσω από τους χρήστες του κωδικού μου να διαβάσουν προσεκτικά τον κώδικά μου για να γνωρίζουν ποιες παραμέτρους παρέχονται με ποια σειρά στον πίνακα ή συλλογή ή ποια τιμή είναι ποια στο tuple, τα αντικείμενα προσαρμοσμένης επιστροφής μου μπορούν να έχουν μεθόδους καθορισμένες αυτοί που λένε στον πελάτη τι ακριβώς παρέχει.

Τα αποσπάσματα κώδικα που ακολουθούν απεικονίζουν ένα απλό Ταινία κλάση που δημιουργείται σε μεγάλο βαθμό από NetBeans που μπορεί να χρησιμοποιηθεί ως τύπος επιστροφής μαζί με τον κώδικα που θα μπορούσε να επιστρέψει μια παρουσία αυτής της κλάσης παρά μια πιο γενική και λιγότερο ευανάγνωστη δομή δεδομένων.

Movie.java

πακέτο dustin.example; εισαγωγή java.util.Objects; / ** * Απλή κλάση ταινιών για να δείξει πόσο εύκολο είναι να παρέχει πολλαπλές τιμές * σε μία μέθοδο Java επιστροφής και να παρέχει αναγνωσιμότητα στον πελάτη. * * @author Dustin * / δημόσια τάξη Ταινία {private final String movieTitle; ιδιωτικό τελικό ενδιάμεσο έτος Κυκλοφόρησε ιδιωτικό τελικό String movieDirectorName; ιδιωτική τελική ταινία StringRating; δημόσια ταινία (String movieTitle, int yearReleased, String movieDirectorName, String movieRating) {this.movieTitle = movieTitle; this.yearReleased = yearReleased; this.movieDirectorName = movieDirectorName; this.movieRating = ταινία Βαθμολογία; } δημόσια συμβολοσειρά getMovieTitle () {return movieTitle; } δημόσια int getYearReleased () {return yearReleased; } δημόσια συμβολοσειρά getMovieDirectorName () {return movieDirectorName; } δημόσια συμβολοσειρά getMovieRating () {return movieRating; } @Override public int hashCode () {int hash = 3; hash = 89 * hash + Objects.hashCode (this.movieTitle); hash = 89 * hash + this.yearReleased; hash = 89 * hash + Objects.hashCode (this.movieDirectorName); hash = 89 * hash + Objects.hashCode (this.movieRating); επιστροφή κατακερματισμού; } @Override public boolean ισούται με (Object obj) {if (obj == null) {return false; } if (getClass ()! = obj.getClass ()) {επιστροφή false; } final Movie other = (Ταινία) obj; if (! Objects.equals (this.movieTitle, other.movieTitle)) {επιστροφή false; } if (this.yearReleased! = other.yearReleased) {επιστροφή false; } if (! Objects.equals (this.movieDirectorName, other.movieDirectorName)) {επιστροφή false; } if (! Objects.equals (this.movieRating, other.movieRating)) {επιστροφή false; } επιστροφή αληθινή; } @Override public String toString () {return "Movie {" + "movieTitle =" + movieTitle + ", yearReleased =" + yearReleased + ", movieDirectorName =" + movieDirectorName + ", movieRating =" + movieRating + '}'; }} 

Επιστροφή πολλαπλών λεπτομερειών σε ένα αντικείμενο

 / ** * Παρέχετε πληροφορίες ταινίας. * * @return Πληροφορίες ταινίας. * / public Movie getMovieInfo () {return new Movie ("Oblivion", 2013, "Joseph Kosinski", "PG-13"); } 

Η απλή γραφή του Ταινία η τάξη μου πήρε περίπου 5 λεπτά. Χρησιμοποίησα τον οδηγό δημιουργίας τάξης NetBeans για να επιλέξω το όνομα και το πακέτο της τάξης και μετά πληκτρολόγησα τα τέσσερα χαρακτηριστικά της τάξης. Από εκεί, απλώς χρησιμοποίησα τον μηχανισμό "Εισαγωγή κώδικα" του NetBeans για να εισαγάγω μεθόδους πρόσβασης "get" μαζί με μεθόδους overridden toString (), hashCode () και ίσες με (Object). Αν δεν πίστευα ότι χρειαζόμουν κάτι τέτοιο, θα μπορούσα να κρατήσω την τάξη πιο απλή, αλλά είναι πραγματικά εύκολο να δημιουργηθεί ως έχει. Τώρα, έχω έναν πολύ πιο χρήσιμο τύπο επιστροφής και αυτό αντικατοπτρίζεται από τον κώδικα που χρησιμοποιεί την κλάση. Δεν χρειάζεται σχεδόν τόσα σχόλια Javadoc για τον τύπο επιστροφής, επειδή αυτός ο τύπος μιλά από μόνος του και διαφημίζει το περιεχόμενό του με τις μεθόδους "get". Πιστεύω ότι η μικρή προσπάθεια δημιουργίας αυτών των απλών τάξεων για την επιστροφή πολλαπλών τιμών αποδίδει με τεράστια μερίσματα σε σύγκριση με εναλλακτικές λύσεις όπως η κατάσταση επιστροφής μέσω παραμέτρων μεθόδου ή η χρήση πιο γενικών και δυσκολότερων στη χρήση δομών δεδομένων επιστροφής.

Δεν προκαλεί μεγάλη έκπληξη το γεγονός ότι ένας προσαρμοσμένος τύπος για τη συγκράτηση των πολλαπλών τιμών για επιστροφή σε έναν καλούντα είναι μια ελκυστική λύση. Σε τελική ανάλυση, αυτό είναι εννοιολογικά πολύ παρόμοιο με τις έννοιες που έγραψα στο παρελθόν σχετικά με τη χρήση προσαρμοσμένων τύπων και παραμέτρων αντικειμένων για μετάδοση σε πολλές σχετικές παραμέτρους αντί παράδοσης όλων σε ξεχωριστά. Η Java είναι μια αντικειμενοστρεφής γλώσσα και έτσι με εκπλήσσει όταν δεν βλέπω αντικείμενα που χρησιμοποιούνται πιο συχνά στον κώδικα Java για την οργάνωση παραμέτρων ΚΑΙ επιστροφών τιμών σε ένα ωραίο πακέτο.

Οφέλη και πλεονεκτήματα

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

Κόστος και μειονεκτήματα

Βλέπω πολύ μικρό μειονέκτημα στη σύνταξη προσαρμοσμένων τύπων με πολλαπλές τιμές που θα χρησιμοποιηθούν ως τύποι επιστροφής από μεθόδους Java. Ίσως το πιο συχνά απαιτούμενο κόστος είναι η τιμή γραφής και δοκιμής αυτών των τάξεων, αλλά αυτό το κόστος είναι πολύ μικρό επειδή αυτά τα μαθήματα τείνουν να είναι απλά και επειδή τα σύγχρονα IDE κάνουν το μεγαλύτερο μέρος της δουλειάς για εμάς. Επειδή οι IDE το κάνουν αυτόματα, ο κωδικός είναι συνήθως σωστός. Τα μαθήματα είναι τόσο απλά που είναι εύκολα αναγνώσιμα από αναθεωρητές κώδικα και είναι εύκολο να δοκιμαστούν.

$config[zx-auto] not found$config[zx-overlay] not found