Ohjelmointi

Java Tip 99: Automatisoi toString () -luonti

Suurten projektien parissa työskentelevät kehittäjät käyttävät yleensä tuntikausia hyödyllisten kirjoittamiseen merkkijono menetelmiä. Vaikka kukin luokka ei saisi omaa merkkijono menetelmä, jokainen tietosäiliöluokka tekee Antaa jokaiselle kehittäjälle kirjoittaa merkkijono hänen oma tapansa voi johtaa kaaokseen; jokainen kehittäjä tulee epäilemättä keksimään ainutlaatuisen muodon. Tämän seurauksena lähdön käyttäminen virheenkorjauksen aikana on vaikeampaa kuin on tarpeen ilman mitään selvää hyötyä. Siksi jokaisen projektin tulisi standardoitua yhdelle muodolle merkkijono menetelmiä ja automatisoi sitten niiden luomisen.

Automatisoi toStringiin

Esittelen nyt apuohjelman, jolla voit tehdä juuri sen. Tämä työkalu luo automaattisesti säännöllisen ja vankan

merkkijono

menetelmä tietylle luokalle, melkein eliminoi menetelmän kehittämiseen kuluva aika. Se myös keskittää

toString ()

muoto. Jos muutat muotoa, sinun on luotava uudelleen

merkkijono

menetelmät; tämä on kuitenkin paljon helpompaa kuin satojen tai tuhansien luokkien manuaalinen muuttaminen.

Luodun koodin ylläpito on myös helppoa. Jos lisäät luokkiin enemmän määritteitä, sinua saatetaan joutua tekemään muutokset merkkijono menetelmä myös. Sukupolven jälkeen merkkijono menetelmät on automatisoitu, sinun tarvitsee vain suorittaa luokan apuohjelma uudelleen tehdäksesi muutoksia. Tämä on yksinkertaisempaa ja vähemmän virhealtista kuin manuaalinen lähestymistapa.

Koodi

Tätä artikkelia ei ole tarkoitettu selittämään Reflection API: ta; seuraava koodi olettaa, että sinulla on ainakin ymmärrys pohdinnan taustalla olevista käsitteistä. Voit käydä

Resurssit

osio Reflection API: n dokumentaatiosta. Apuohjelma on kirjoitettu seuraavasti:

paketti fareed.publications.utilities; tuo java.lang.reflect. *; public class ToStringGenerator {public static void main (String [] args) {if (args.length == 0) {System.out.println ("Anna luokan nimi komentoriviargumenttina"); System.exit (0); } kokeile {Class targetClass = Class.forName (argumentit [0]); if (! targetClass.isPrimitive () && targetClass! = String.class) {Kenttäkentät [] = targetClass.getDeclaredFields (); Luokka cSuper = targetClass.getSuperclass (); // Noudetaan superluokan lähtö ("StringBuffer-puskuri = uusi StringBuffer (500);"); // Puskurirakenne if (cSuper! = Null && cSuper! = Object.class) {output ("buffer.append (super.toString ());"); // Super-luokan toString ()} (int j = 0; j <kentät.pituus; j ++) {-lähtö ("puskuri.suhde (\" "+ kentät [j] .getName () +" = \ "); "); // Liitä kentän nimi, jos (kentät [j] .getType (). IsPrimitive () || kentät [j] .getType () == String.class) // Tarkista, onko primitiivinen tai merkkijono ("buffer.append ( tämä. "+ kentät [j] .getName () +"); "); // Liitä primitiivikentän arvo muu {/ * Se EI ole primitiivinen kenttä, joten tämä edellyttää kootun objektin * / output NULL-arvon tarkistusta ("if (tämä." + Kentät [j] .getName () + "! = null)"); output ("buffer.append (this." + kentät [j] .getName () + ".toString ());"); output ("else buffer.append (\" arvo on tyhjä \ ");"); } // loppu muusta} // silmukan ulostulon loppu ("return buffer.toString ();"); }} catch (ClassNotFoundException e) {System.out.println ("Luokkaa ei löydy luokan polusta"); System.exit (0); }} yksityinen staattinen tyhjä tulos (merkkijonodata) {System.out.println (data); }} 

Koodilähtökanava

Koodin muoto riippuu myös projektityökalun vaatimuksista. Jotkut kehittäjät saattavat mieluummin pitää koodin käyttäjän määrittelemässä tiedostossa levyllä. Muut kehittäjät ovat tyytyväisiä

system.out

konsolin, jonka avulla he voivat kopioida ja upottaa koodin todelliseen tiedostoon manuaalisesti. Jätän nuo vaihtoehdot yksinkertaisesti sinulle ja käytän yksinkertaisinta menetelmää:

system.out

lausunnot.

Lähestymistavan rajoitukset

Tähän lähestymistapaan liittyy kaksi tärkeää rajoitusta. Ensimmäinen on, että se ei tue syklejä sisältäviä objekteja. Jos objekti A sisältää viitteen objektille B, joka sitten sisältää viitteen objektille A, tämä työkalu ei toimi. Kuitenkin tapaus on harvinaista monissa hankkeissa.

Toinen rajoitus on, että jäsenmuuttujien lisääminen tai vähentäminen vaatii merkkijono menetelmä. Koska tämä on tehtävä työkalulla tai ilman, se ei ole tämän lähestymistavan erityinen ongelma.

Johtopäätös

Tässä artikkelissa olen selittänyt pienen automaatioapuohjelman, joka voi todella parantaa kehittäjien tuottavuutta ja jolla on pieni mutta tärkeä rooli projektin kokonaisaikataulujen lyhentämisessä.


Seurantavinkit

Kun tämä vinkki on julkaistu, sain lukijoilta muutamia ehdotuksia koodin parantamiseksi. Tässä seurannassa selitän, kuinka olen päivittänyt apuohjelman näiden ehdotusten ja omien oivallusteni perusteella. Näiden parannusten lähdekoodi löytyy Resursseista.

Parannus nro 1, ehdottanut Sangeeta Varma

Alkuperäisessä koodissani en käsitellyt objekti- ja primitiivisten tietotyyppien taulukotyyppejä; uusi koodi käsittelee nyt taulukon tietoja. Koodi kuitenkin nousee vain yhden ulottuvuuden matriiseihin eikä toimi useiden ulottuvuuksien ryhmissä. En ole kyennyt keksimään yleistä ratkaisua tähän ongelmaan, koska parhaan tietoni mukaan Java-tietotyyppien ulottuvuuksien määrälle ei ole rajoituksia (ainoa rajoitus on käytettävissä oleva muisti). Olen tyytyväinen kaikkiin palautteisiin, joita voit tarjota ratkaisuun.

Parannus nro 2, ehdotti Chris Sanscraint

Alun perin ehdotin hyödyllisyyttä kehitysaikaan eikä ajo-ympäristöön. Antaa apuohjelman käydä ajon aikana voi olla erittäin kätevää, mutta se voi viedä vielä muutaman suorittimen jakson. Objektin polkumyynti / virheenkorjaus ( toString ()) tehdään yleensä kehitysajan aikana ja kytketään pois päältä tuotantoympäristöä varten. Joissakin tapauksissa tätä poiskytkentää tuotantoympäristössä ei ehkä voida soveltaa, koska jotkut projektit saattavat käyttää sitä toString () liiketoimintalogiikan tarkoituksiin. Ehdotan, että päätös tehdään hankekohtaisesti.

Ennen tämän apuohjelman kehittämistä minulla oli jo tämä ajonaikainen joustavuus mielessäni. Ensinnäkin kehitin erillisen delegointiluokan, jota kaikki asiakasluokat käyttivät toString (). Luokka loi sen käyttämällä menetelmäkutsu kaltaista palaa ToStringGenerator.generateToString (tämä), missä Tämä osoittaa asiakasluokan nykyisen esiintymän ja koodilauseke kirjoitetaan toString () menetelmän toteutus. Mutta tämä lähestymistapa epäonnistui, koska Reflection-sovellusliittymällä ei ole kykyä saada arvoja yksityisille jäsenille ajon aikana. Joten luokka oli hyödyllinen vain julkisille jäsenille, mitä en halunnut.

Mutta sitten herra Sanscraint huomautti, että sama Reflection API-koodi saa yksityisten jäsenten arvon ajon aikana, kun koodi kirjoitetaan saman soittajaluokan menetelmään. Joten olen päivittänyt ajon aikana käytettävän apuohjelman ja lisäksi toString () menetelmää ei koskaan tarvitse päivittää tai muokata minkä tahansa kohdeluokan attribuutin vähentämiseksi tai lisäämiseksi.

Parannus # 3, ehdottanut Eric Ye

Alun perin käytin Tämä etuliite jäsenmuuttujien pääsyyn luodussa koodissa, mutta herra Ye huomautti, että koodia voidaan käyttää myös staattisessa menetelmässä tai jopa staattisten jäsenten tuottamiseksi. Joten päivitetty koodi pystyy nyt käsittelemään sekä luokan että instanssin jäseniä. Herra Ye tunnisti myös virheen, joka on korjattu tässä versiossa, joka sai luokan luomaan hyödytöntä koodia määritteettömille luokille.

Koodimuutokset

Kun olin tehnyt apuohjelman ajonaikaisen, olin turhautunut siitä, että jouduin kopioimaan / liittämään kussakin luokassa olevat menetelmät, mikä vaikeutui, koska uusi koodi koostui useista menetelmistä.

Yksi ratkaisu olisi luoda käyttöliittymä / abstrakti perusluokka, joka ainakin ratkaisisi metodin allekirjoitusten ongelman, mutta silti tarvitaan kopiointia / liittämistä. Abstrakti perusluokan ratkaisu myös estäisi asiakasta tulemasta toisesta luokasta.

Sisäisellä luokalla on kuitenkin kyky käyttää vanhempien luokan yksityisiä jäseniä, joten sen menetelmien sisällä toimiva heijastuskoodi voisi saada myös yksityiset arvot. Joten päätin vaihtaa apuohjelman sisäiseen luokkaan, joka voidaan lisätä mihin tahansa pääasiakasluokkaan. Olen myös toimittanut ToStringGeneratorExample.java-sovelluksen, joka käyttää ToStringGenerator.java-sovellusta sisäisenä luokkana toString () menetelmä.

Lopuksi haluan kiittää niitä ihmisiä, jotka esittivät ehdotuksiaan tämän lähestymistavan parantamiseksi.

Syed Fareed Ahmad on Java-ohjelmoija, suunnittelija ja arkkitehti Lahoressa, Pakistanissa. Hän on mukana Java- (Servlet-, JSP- ja EJB), WebSphere- ja XML-pohjaisten sähköisen liiketoiminnan ratkaisujen kehittämisessä.

Lisätietoja tästä aiheesta

  • Seurantalähdekoodia varten

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

  • Pohdinta-asiakirjat Sunin verkkosivustolla

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

  • Näytä kaikki edelliset Java-vinkkejä ja lähetä oma

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

Tämän tarinan, "Java Tip 99: Automate toString () creation", julkaisi alun perin JavaWorld.