Ohjelmointi

Käsitellään komentoriviargumentteja Java: Tapaus suljettu

Monet komentoriviltä aloitetut Java-sovellukset ottavat argumentteja hallitsemaan käyttäytymistään. Nämä argumentit ovat käytettävissä merkkijonoryhmäargumentissa, joka välitetään sovelluksen staattiseen muotoon main () menetelmä. Tyypillisesti argumentteja on kahden tyyppisiä: vaihtoehdot (tai kytkimet) ja todelliset data-argumentit. Java-sovelluksen on käsiteltävä nämä argumentit ja suoritettava kaksi perustehtävää:

  1. Tarkista, onko käytetty syntakse voimassa ja tuettu
  2. Nouda tosiasialliset tiedot, joita sovellus tarvitsee toimintojensa suorittamiseen

Usein koodi, joka suorittaa nämä tehtävät, on räätälöity jokaiselle sovellukselle ja vaatii siten huomattavia ponnisteluja sekä luomiseksi että ylläpitämiseksi, varsinkin jos vaatimukset ylittävät yksinkertaiset tapaukset, joissa on vain yksi tai kaksi vaihtoehtoa. Vaihtoehdot Tässä artikkelissa kuvattu luokka toteuttaa yleisen lähestymistavan monimutkaisimpien tilanteiden käsittelemiseksi helposti. Luokka mahdollistaa tarvittavien vaihtoehtojen ja data-argumenttien yksinkertaisen määrittelyn ja tarjoaa perusteelliset syntaksitarkistukset ja helpon pääsyn näiden tarkastusten tuloksiin. Uusia Java 5 -ominaisuuksia, kuten geneerisiä aineita ja tyyppikohtaisia ​​käyttöohjeita, käytettiin myös tässä projektissa.

Komentorivin argumenttityypit

Vuosien varrella olen kirjoittanut useita Java-työkaluja, jotka käyttävät komentoriviargumentteja käyttäytymisensä hallitsemiseksi. Aikaisin, minusta tuntui ärsyttävältä luoda ja ylläpitää koodi manuaalisesti eri vaihtoehtojen käsittelyä varten. Tämä johti prototyyppiluokan kehittämiseen tämän tehtävän helpottamiseksi, mutta tällä luokalla oli tosin rajoituksia, koska tarkassa tarkastelussa komentoriviargumenttien mahdollisten erilaisten lajikkeiden lukumäärä osoittautui merkittäväksi. Lopulta päätin kehittää yleisen ratkaisun tähän ongelmaan.

Kehitettäessä tätä ratkaisua jouduin ratkaisemaan kaksi pääongelmaa:

  1. Määritä kaikki lajikkeet, joissa komentorivivaihtoehtoja voi esiintyä
  2. Etsi yksinkertainen tapa antaa käyttäjien ilmaista nämä lajikkeet käyttäessään vielä kehitettävää luokkaa

Tehtävän 1 analyysi johti seuraaviin havaintoihin:

  • Komentorivivalinnat, toisin kuin komentorividata-argumentit - aloita etuliitteellä, joka tunnistaa ne yksiselitteisesti. Etuliiteesimerkit sisältävät viivan (-) Unix-alustoilla -a tai kauttaviiva (/) Windows-alustoilla.
  • Vaihtoehdot voivat olla joko yksinkertaisia ​​kytkimiä (ts. -a voi olla läsnä tai ei) tai ottaa arvo. Esimerkiksi:

    java MyTool -a -b logfile.inp 
  • Arvoa ottavissa vaihtoehdoissa voi olla erilaisia ​​erottimia todellisen valintanäppäimen ja arvon välillä. Tällaiset erottimet voivat olla tyhjä tila, kaksoispiste (:) tai yhtäläisyysmerkki (=):

    java MyTool -a -b logfile.inp java MyTool -a -b: logfile.inp java MyTool -a -b = logfile.inp 
  • Arvoa ottavat vaihtoehdot voivat lisätä vielä yhden monimutkaisuuden tason. Harkitse esimerkkinä tapaa, jolla Java tukee ympäristöominaisuuksien määrittelyä:

    java -Djava.library.path = / usr / lib ... 
  • Joten todellisen optioavaimen (D.), erotin (=) ja option todellinen arvo (/ usr / lib), lisäparametri (java.library.path) voi ottaa minkä tahansa määrän arvoja (yllä olevassa esimerkissä voidaan määrittää useita ympäristöominaisuuksia tällä syntaksilla). Tässä artikkelissa tätä parametria kutsutaan nimellä "yksityiskohta".
  • Vaihtoehdoilla on myös moninaisuusominaisuus: ne voivat olla pakollisia tai valinnaisia, ja sallittujen kertojen määrä voi myös vaihdella (kuten täsmälleen kerran, kerran tai useammin tai muita mahdollisuuksia).
  • Tietoargumentit ovat kaikki komentoriviargumentteja, jotka eivät ala etuliitteellä. Tällöin hyväksyttävä määrä tällaisia ​​data-argumentteja voi vaihdella pienimmän ja enimmäismäärän välillä (jotka eivät välttämättä ole samat). Lisäksi tyypillisesti sovellus edellyttää, että nämä argumentit ovat viimeisiä komentorivillä, mutta sen ei tarvitse aina olla. Esimerkiksi:

    java MyTool -a -b = lokitiedosto.inp data1 data2 data3 // Kaikki tiedot lopussa 

    tai

    java MyTool -a data1 data2 -b = logfile.inp data3 // Voi olla hyväksyttävä sovellukselle 
  • Monimutkaisemmat sovellukset voivat tukea useita vaihtoehtoja:

    java MyTool -a -b datafile.inp java MyTool -k [-verbose] foo bar duh java MyTool -check -verify logfile.out 
  • Lopuksi sovellus voi halutessaan jättää tuntemattomat vaihtoehdot huomiotta tai pitää tällaisia ​​vaihtoehtoja virheinä.

Joten suunnitellessani tapaa antaa käyttäjien ilmaista kaikki nämä lajikkeet, keksin seuraavan yleisen vaihtoehtolomakkeen, jota käytetään tämän artikkelin perustana:

[[]] 

Tämä muoto on yhdistettävä moninaisuusominaisuuteen, kuten edellä on kuvattu.

Edellä kuvatun vaihtoehdon yleisen muodon rajoissa Vaihtoehdot Tässä artikkelissa kuvattu luokka on suunniteltu yleiseksi ratkaisuksi kaikkiin Java-sovelluksen komentorivin käsittelytarpeisiin.

Auttaja luokat

Vaihtoehdot class, joka on tässä artikkelissa kuvatun ratkaisun ydinluokka, sisältää kaksi auttajaluokkaa:

  1. OptionData: Tämä luokka sisältää kaikki tiedot tietystä vaihtoehdosta
  2. OptionSet: Tässä luokassa on joukko vaihtoehtoja. Vaihtoehdot itsessään voi olla mikä tahansa määrä tällaisia ​​sarjoja

Ennen näiden luokkien yksityiskohtien kuvaamista muita tärkeitä käsitteitä Vaihtoehdot luokka on otettava käyttöön.

Typesafe enums

Etuliite, erotin ja moninaisuusominaisuus on kaapattu enumien avulla, ominaisuus, jonka Java 5 tarjoaa ensimmäisen kerran:

public enum -etuliite {DASH ('-'), SLASH ('/'); yksityinen merkki; yksityinen etuliite (char c) {this.c = c; } char getName () {return c; }} public enum Separator {COLON (':'), EQUALS ('='), TYHJÄ (''), NONE ('D'); yksityinen merkki; yksityinen erotin (char c) {this.c = c; } char getName () {return c; }} public enum Moninaisuus {ONCE, ONCE_OR_MORE, ZERO_OR_ONE, ZERO_OR_MORE; } 

Enumien käytöllä on joitain etuja: lisääntynyt tyyppiturvallisuus ja tiukka, vaivaton hallinta sallittujen arvojen joukossa. Enumeja voidaan käyttää kätevästi myös geneeristen kokoelmien kanssa.

Huomaa, että Etuliite ja Erotin enumeilla on omat rakentajansa, mikä mahdollistaa todellisen määritelmän merkki joka edustaa tätä enum-instanssia (vs. nimi käytetään viittaamaan tiettyyn luettelotapaukseen). Nämä merkit voidaan hakea näiden enumien avulla ' getName () menetelmiä, ja merkkejä käytetään java.util.regex paketin kuviosyntaksi. Tätä pakettia käytetään suorittamaan joitakin syntaksitarkistuksia Vaihtoehdot luokka, jonka yksityiskohdat seuraavat.

Moninaisuus enum tukee tällä hetkellä neljää erilaista arvoa:

  1. KERRAN: Vaihtoehdon on tapahduttava täsmälleen kerran
  2. ONCE_OR_MORE: Vaihtoehdon on oltava vähintään kerran
  3. ZERO_OR_ONCE: Vaihtoehto voi olla poissa tai olla läsnä täsmälleen kerran
  4. ZERO_OR_MORE: Vaihtoehto voi joko olla poissa tai se voi esiintyä useita kertoja

Lisää määritelmiä voidaan helposti lisätä tarvittaessa.

OptionData-luokka

OptionData luokka on pohjimmiltaan tietosäiliö: ensinnäkin itse vaihtoehtoa kuvaaville tiedoille ja toiseksi kyseisen vaihtoehdon komentoriviltä löydetyille tiedoille. Tämä malli heijastuu jo rakentajaan:

OptionData (Asetukset.Etuliitteen etuliite, Merkkijonoavain, totuusarvoinen yksityiskohdat, Asetukset.Erottimen erotin, looginen arvo, Asetukset.Moninkertaisuuden moninkertaisuus) 

Avainta käytetään tämän vaihtoehdon yksilöllisenä tunnuksena. Huomaa, että nämä argumentit heijastavat suoraan aiemmin kuvattuja havaintoja: täydellisessä vaihtoehdon kuvauksessa on oltava vähintään etuliite, avain ja monikertaisuus. Arvoa ottavissa vaihtoehdoissa on myös erotin, ja ne saattavat hyväksyä yksityiskohdat. Huomaa myös, että tällä konstruktorilla on pakettipääsy, joten sovellukset eivät voi käyttää sitä suoraan. Luokka OptionSeton addOption () method lisää vaihtoehdot. Tällä suunnitteluperiaatteella on se etu, että voimme hallita paljon paremmin todellisia mahdollisia argumenttiyhdistelmiä, joita käytetään luomiseen OptionData tapauksia. Jos tämä rakentaja olisi esimerkiksi julkinen, voit luoda ilmentymän, jonka yksityiskohdat on asetettu totta ja arvoksi asetettu väärä, mikä on tietysti hölynpölyä. Sen sijaan, että tekisin monimutkaisia ​​tarkastuksia itse rakentajasta, päätin tarjota valvotun sarjan addOption () menetelmiä.

Rakentaja luo myös instanssin java.util.regex.Pattern, jota käytetään tämän vaihtoehdon mallinnusprosessissa. Yksi esimerkki olisi malli vaihtoehdolle, joka ottaa arvon, ei yksityiskohtia ja erottimen, joka ei ole tyhjä:

kuvio = java.util.regex.Pattern.compile (etuliite.getName () + avain + separator.getName () + "(. +) $"); 

OptionData - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Kuten - jo mainittiin, luokassa on myös, kuten jo mainittiin, myös Vaihtoehdot luokassa. Se tarjoaa seuraavat julkiset menetelmät näiden tulosten saamiseksi:

int getResultCount () Merkkijono getResultValue (int-indeksi) Merkkijono getResultDetail (int-indeksi) 

Ensimmäinen menetelmä, getResultCount (), palauttaa vaihtoehdon löytämiskertojen määrän. Tämä menetelmän suunnittelu liittyy suoraan vaihtoehdolle määritettyyn moninaisuuteen. Jos arvo on arvo, tämän arvon voi noutaa käyttämällä getResultValue (int-indeksi) menetelmä, jossa indeksi voi vaihdella välillä 0 ja getResultCount () - 1. Arvovaihtoehdoille, jotka hyväksyvät myös yksityiskohdat, niihin pääsee vastaavasti käyttämällä getResultDetail (int-indeksi) menetelmä.

OptionSet-luokka

OptionSet luokka on pohjimmiltaan kontti joukolle OptionData esiintymiä ja myös komentoriviltä löytyneet data-argumentit.

Rakentajalla on muoto:

OptionSet (Asetukset.Etuliitteen etuliite, Asetukset.Multiplicity defaultMultiplicity, String setName, int minData, int maxData) 

Jälleen tällä konstruktorilla on pääsy pakettiin. Vaihtoehtojoukkoja voidaan luoda vain Vaihtoehdot luokka on erilainen addSet () menetelmiä. Tässä määritettyjen vaihtoehtojen oletuskerroin voidaan ohittaa, kun lisätään vaihtoehto sarjaan. Tässä määritetty joukon nimi on yksilöllinen tunniste, jota käytetään viittaamaan sarjaan. minData ja maxData ovat tämän ryhmän hyväksyttävien data-argumenttien vähimmäis- ja enimmäismäärä.

Verkkotunnuksen julkinen sovellusliittymä OptionSet sisältää seuraavat menetelmät:

Yleiset käyttömenetelmät:

Merkkijono getSetName () int getMinData () int getMaxData () 

Menetelmät vaihtoehtojen lisäämiseksi:

OptionSet addOption (merkkijonoavain) OptionSet addOption (merkkijonoavain, monikertaisuus) OptionSet addOption (merkkijonoavain, erotinerotin) OptionSet addOption (merkkijonoavain, erotinerotin, moninkertaisuuskerroin) OptionSet addOption (merkkijonoavain, boolen tiedot, erotinerotin) (Merkkijonoavain, totuusarvotiedot, erotinerotin, moninkertaisuus) 

Menetelmät tarkastustulosten tietojen saamiseksi:

java.util.ArrayList getOptionData () OptionData getOption (String key) looginen isSet (String key) java.util.ArrayList getData () java.util.ArrayList getUnmatched () 

Huomaa, että menetelmät, joilla lisätään vaihtoehtoja a Erotin argumentti luo OptionData esimerkiksi hyväksymällä arvon. addOption () metodit palauttavat itse asetetun esiintymän, mikä sallii kutsuketjun:

Vaihtoehtovaihtoehdot = uusi Asetukset (argumentit); options.addSet ("MySet"). addOption ("a"). addOption ("b"); 

Kun tarkastukset on suoritettu, niiden tulokset ovat käytettävissä jäljellä olevilla menetelmillä. getOptionData () palauttaa luettelon kaikista OptionData esimerkiksi getOption () sallii suoran pääsyn tiettyyn vaihtoehtoon. isSet (merkkijono-avain) on mukavuusmenetelmä, joka tarkistaa, löydettiinkö vaihtoehdot ainakin kerran komentoriviltä. getData () tarjoaa pääsyn löydettyihin tietoargumentteihin, kun taas getUnmatched () luetellaan kaikki komentoriviltä löytyneet vaihtoehdot, joille ei ole hakua OptionData tapauksia löydettiin.

Options-luokka

Vaihtoehdot on ydinluokka, jonka kanssa sovellukset ovat vuorovaikutuksessa. Se tarjoaa useita rakentajia, jotka kaikki ottavat komentorivin argumenttimerkkijonoryhmän, jonka main () menetelmä tarjoaa ensimmäisenä argumenttina:

Asetukset (String args []) Asetukset (String args [], int data) Asetukset (String args [], int defMinData, int defMaxData) Asetukset (String args [], Multiplicity defaultMultiplicity) Vaihtoehdot (String args [], Multiplicity defaultMultiplicity, int data) Asetukset (String args [], Multiplicity defaultMultiplicity, int defMinData, int defMaxData) Options (String args [], Prefix prefix) Options (String args [], Prefix prefix, int data) Options (String args [], Prefix etuliite, int defMinData, int defMaxData) Asetukset (String args [], Prefix prefix, Multiplicity defaultMultiplicity) Options (String args [], Prefix prefix, Multiplicity defaultMultiplicity, int data) Options (String args [], Prefix prefix, Multiplicity defaultMultiplicity, int defMinData, int defMaxData) 

Tämän luettelon ensimmäinen rakentaja on yksinkertaisin, joka käyttää kaikkia oletusarvoja, kun taas viimeinen on yleisin.

Taulukko 1: Argumentit Options () -rakentajille ja niiden merkitykselle

Arvo Kuvaus Oletus
etuliiteTämä konstruktorin argumentti on ainoa paikka, jossa etuliite voidaan määrittää. Tämä arvo välitetään mille tahansa vaihtoehtojoukolle ja kaikille myöhemmin luotuille vaihtoehdoille. Tämän lähestymistavan idea on, että tietyssä sovelluksessa on epätodennäköistä, että eri etuliitteitä on käytettävä.Etuliite: DASH
defaultMultiplicityTämä oletuskerroin välitetään kullekin vaihtoehtojoukolle ja sitä käytetään oletusarvoina sarjaan lisätyille vaihtoehdoille määrittelemättä moninkertaisuutta. Tietysti tämä moninaisuus voidaan ohittaa jokaiselle lisätylle vaihtoehdolle.Moninaisuus
defMinDatadefMinData on oletettujen vähimmäismäärä tuettuja data-argumentteja, jotka on välitetty kullekin vaihtoehtojoukolle, mutta se voidaan tietysti ohittaa, kun joukko lisätään.0
defMaxDatadefMaxData on oletusarvoinen tuettujen data-argumenttien lukumäärä, joka välitetään kullekin vaihtoehtojoukolle, mutta se voidaan tietysti ohittaa, kun joukko lisätään.0