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

Java Tip 99: Αυτοματοποίηση δημιουργίας toString ()

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

Αυτοματοποίηση toString

Θα δείξω τώρα ένα βοηθητικό πρόγραμμα με το οποίο μπορείτε να κάνετε ακριβώς αυτό. Αυτό το εργαλείο δημιουργεί αυτόματα ένα κανονικό και στιβαρό

toString

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

toString ()

μορφή. Εάν αλλάξετε τη μορφή, πρέπει να αναδημιουργήσετε το

toString

μέθοδοι Ωστόσο, αυτό είναι ακόμα πολύ πιο εύκολο από το να αλλάζεις χειροκίνητα εκατοντάδες ή χιλιάδες μαθήματα.

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

Ο κώδικας

Αυτό το άρθρο δεν έχει σκοπό να εξηγήσει το Reflection API. Ο παρακάτω κώδικας προϋποθέτει ότι έχετε τουλάχιστον μια κατανόηση των εννοιών πίσω από το Reflection. Μπορείτε να επισκεφθείτε το

Πόροι

ενότητα για την τεκμηρίωση του Reflection API. Το βοηθητικό πρόγραμμα γράφεται ως εξής:

πακέτο fareed.publications.utilities; εισαγωγή java.lang.reflect. *; δημόσια τάξη ToStringGenerator {public static void main (String [] args) {if (args.length == 0) {System.out.println ("Δώστε το όνομα της κλάσης ως όρισμα γραμμής εντολών"); System.exit (0); } δοκιμάστε το {Class targetClass = Class.forName (args [0]); if (! targetClass.isPrimitive () && targetClass! = String.class) {Πεδία πεδίου [] = targetClass.getDeclaredFields (); Κατηγορία cSuper = targetClass.getSuperclass (); // Ανάκτηση της εξόδου super class ("StringBuffer buffer = new StringBuffer (500);"); // Buffer Construction if (cSuper! = Null && cSuper! = Object.class) {έξοδος ("buffer.append (super.toString ());"); // Super class's toString ()} για (int j = 0; j <fields.length; j ++) {έξοδος ("buffer.append (\" "+ πεδία [j] .getName () +" = \ "); "); // Προσάρτηση ονόματος πεδίου εάν (πεδία [j] .getType (). IsPrimitive () || πεδία [j] .getType () == String.class) // Έλεγχος για πρωτόγονο ή έξοδο συμβολοσειράς ("buffer.append ( αυτό. "+ πεδία [j] .getName () +"); "); // Προσθέστε την αρχική τιμή πεδίου αλλιώς {/ * ΔΕΝ είναι πρωτόγονο πεδίο, επομένως αυτό απαιτεί έλεγχο για την τιμή NULL για το συγκεντρωτικό αντικείμενο * / έξοδο ("if (this." + Πεδία [j] .getName () + "! = null)"); έξοδος ("buffer.append (this." + πεδία [j] .getName () + ".toString ());"); έξοδος ("else buffer.append (\" η τιμή είναι null \ ");"); } // end of else} // τέλος για έξοδο βρόχου ("return buffer.toString ();"); }} catch (ClassNotFoundException e) {System.out.println ("Η κλάση δεν βρέθηκε στη διαδρομή κλάσης"); System.exit (0); }} ιδιωτική έξοδος στατικού κενού (String data) {System.out.println (data); }} 

Το κανάλι εξόδου κώδικα

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

system.out

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

system.out

δηλώσεις.

Περιορισμοί στην προσέγγιση

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

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

συμπέρασμα

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


Συμβουλές παρακολούθησης

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

Βελτίωση # 1, προτεινόμενη από τη Sangeeta Varma

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

Βελτίωση # 2, προτεινόμενη από τον Chris Sanscraint

Αρχικά πρότεινα τη χρησιμότητα για το χρόνο ανάπτυξης και όχι για το περιβάλλον χρόνου εκτέλεσης. Το να επιτρέπεται η εκτέλεση του βοηθητικού προγράμματος στο χρόνο εκτέλεσης μπορεί να είναι πολύ βολικό, αλλά μπορεί να χρειαστούν μερικοί ακόμη κύκλοι CPU. Ωστόσο, το αντικείμενο ντάμπινγκ / εντοπισμού σφαλμάτων (βασική χρήση του toString ()) γίνεται συνήθως κατά τη διάρκεια του χρόνου ανάπτυξης και απενεργοποιείται για το περιβάλλον παραγωγής. Σε ορισμένες περιπτώσεις, αυτή η απενεργοποίηση στο περιβάλλον παραγωγής ενδέχεται να μην ισχύει καθώς ενδέχεται να χρησιμοποιηθούν ορισμένα έργα toString () για σκοπούς επιχειρηματικής λογικής. Προτείνω να λάβω αυτήν την απόφαση ανά έργο.

Πριν αναπτύξω αυτό το βοηθητικό πρόγραμμα, είχα ήδη στο μυαλό μου αυτήν την ευελιξία χρόνου εκτέλεσης. Πρώτον, ανέπτυξα μια ξεχωριστή τάξη ανάθεσης που χρησιμοποιήθηκε από οποιαδήποτε κλάση πελάτη για τη δημιουργία του toString (). Η τάξη το δημιούργησε χρησιμοποιώντας μια μέθοδο κλήσης όπως επιστροφή ToStringGenerator.generateToString (αυτό), όπου Αυτό δείχνει την τρέχουσα παρουσία της κλάσης πελάτη και η δήλωση κώδικα γράφεται στο toString () εφαρμογή μεθόδου. Αλλά αυτή η προσέγγιση απέτυχε επειδή το Reflection API δεν έχει τη δυνατότητα να πάρει τις τιμές για τα ιδιωτικά μέλη κατά το χρόνο εκτέλεσης. Έτσι, η τάξη ήταν χρήσιμη μόνο για δημόσια μέλη, κάτι που δεν ήθελα.

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

Βελτίωση # 3, προτεινόμενη από τον Eric Ye

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

Τροποποιήσεις κώδικα

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

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

Μια εσωτερική τάξη, ωστόσο, έχει τη δυνατότητα πρόσβασης στα ιδιωτικά μέλη της γονικής τάξης, έτσι ώστε ο κωδικός προβληματισμού, που τρέχει με τις μεθόδους του, να μπορεί επίσης να πάρει τις ιδιωτικές τιμές. Γι 'αυτό αποφάσισα να αλλάξω το βοηθητικό πρόγραμμα σε μια εσωτερική τάξη που θα μπορούσε να εισαχθεί σε οποιαδήποτε μητρική τάξη πελάτη. Έχω επίσης παράσχει ToStringGeneratorExample.java που χρησιμοποιεί το ToStringGenerator.java ως την εσωτερική τάξη για την εφαρμογή του toString () μέθοδος.

Τέλος, θέλω να ευχαριστήσω εκείνους τους ανθρώπους που πρότειναν τις προτάσεις τους για τη βελτίωση αυτής της προσέγγισης.

Ο Syed Fareed Ahmad είναι προγραμματιστής Java, σχεδιαστής και αρχιτέκτονας στο Λαχόρη του Πακιστάν. Συμμετέχει στην ανάπτυξη λύσεων ηλεκτρονικού επιχειρείν που βασίζονται σε Java- (Servlets, JSP και EJB), WebSphere- και XML.

Μάθετε περισσότερα σχετικά με αυτό το θέμα

  • Για τον πηγαίο κώδικα παρακολούθησης

    //images.techhive.com/downloads/idge/imported/article/jvw/2000/08/jw-javatip99.zip

  • Τεκμηρίωση προβληματισμού στον ιστότοπο της Sun

    //java.sun.com/products/jdk/1.1/docs/guide/reflection/index.html

  • Δείτε όλα τα προηγούμενα Συμβουλές Java και υποβάλετε το δικό σας

    //www.javaworld.com/javatips/jw-javatips.index.html

Αυτή η ιστορία, "Java Tip 99: Automate toString () create" δημοσιεύθηκε αρχικά από το JavaWorld.