Ohjelmointi

Kenttien ja menetelmien suunnittelu

Tämän kuukauden erä Suunnittelutekniikat on toinen esineiden suunnittelua käsittelevästä sarakkeesta. Viime kuun sarakkeessa, joka käsitteli esineiden suunnittelua asianmukaista alustamista varten, puhuin rakentajien ja alustajien suunnittelusta. Tässä kuussa ja ensi kuussa keskustelen luokan varsinaisten kenttien ja menetelmien suunnitteluperiaatteista. Sen jälkeen kirjoitan viimeistelijöistä ja näytän, kuinka suunnitella esineitä kunnollista puhdistusta varten heidän elämänsä lopussa.

Tämän artikkelin materiaali (erityisten data-arvojen välttäminen, vakioiden käyttö, kytkennän minimointi) ja seuraava artikkeli (kohimoinnin maksimointi) ja seuraava artikkeli (maksimoivat yhteenkuuluvuuden) voivat olla tuttuja lukijoille, koska materiaali perustuu yleisiin suunnitteluperiaatteisiin, jotka ovat melko riippumattomia Java-ohjelmointikielestä . Koska olen kuitenkin kohdannut vuosien varrella niin paljon koodeja, joissa ei hyödynnetä näitä periaatteita, mielestäni ne ansaitsevat ajoittain uudelleen. Lisäksi yritän tässä artikkelissa osoittaa, kuinka nämä yleiset periaatteet koskevat erityisesti Java-kieltä.

Kenttien suunnittelu

Kenttien suunnittelussa tärkein nyrkkisääntö on välttää yhden muuttujan käyttämistä luokan useiden attribuuttien edustamiseen. Voit rikkoa tätä sääntöä merkitsemällä muuttujan erityisarvot, joilla jokaisella on oma erityinen merkityksensä.

Tässä käytettynä määritteen on kohteen tai luokan erottava ominaisuus. Kaksi a-attribuuttia Kahvikuppi esine voi esimerkiksi olla:

  • Kupin sisältämän kahvin määrä
  • Onko kuppi puhdas vai likainen

Tarkastele tätä sääntöä tarkemmin kuvittelemalla, että suunnittelet Kahvikuppi luokka viime kuussa kuvatulle virtuaalikahvilalle Suunnittelutekniikat sarake. Oletetaan, että haluat mallintaa, onko virtuaalikahvilasi kahvikuppi pesty ja onko seuraava asiakas valmis sitä käyttämään. Näiden tietojen avulla voit varmistaa, että et käytä kahvikuppia uudelleen ennen kuin se on pesty.

Jos päätät, että välität vain siitä, onko kuppi pesty, jos se on tyhjä, voit käyttää kupin erityisarvoa sisäinen kahvi kenttä, jota tavallisesti käytetään pitämään kirjaa kupin kahvimäärästä edustamaan pesemätöntä kuppia. Jos 473 millilitraa (16 nesteunssia) on suurin kahvimäärä suurimmassa kupillessasi, sisäinen kahvi normaalisti olisi 473. Voit siis käyttää sisäinen kahvi arvo esimerkiksi 500 (erikoisarvo) ilmaisemaan tyhjää kuppia, joka on pesemätön:

// Lähdepaketissa tiedostokentissä / ex1 / CoffeeCup.java class CoffeeCup {private int innerCoffee; public boolean isReadyForNextUse () {// Jos kahvikuppi ei ole pesty, se // ei ole valmis seuraavaa käyttöä varten, jos (innerCoffee == 500) {return false; } return true; } public void setCustomerDone () {innerCoffee = 500; // ...} public void wash () {innerCoffee = 0; // ...} // ...} 

Tämä koodi antaa Kahvikuppi vastustaa haluttua käyttäytymistä. Tämän lähestymistavan ongelmana on, että erityisiä arvoja ei ymmärretä helposti, ja ne vaikeuttavat koodin muuttamista. Vaikka kuvailisit erityisiä arvoja kommentissa, muilla ohjelmoijilla voi kestää kauemmin ymmärtää koodisi toimintaa. Lisäksi he eivät ehkä koskaan ymmärrä koodiasi. He voivat käyttää luokkaa väärin tai muuttaa sitä siten, että he tuovat virheen.

Esimerkiksi, jos myöhemmin joku lisää 20 unssin kupin virtuaalikahvilan tarjontaan, olisi mahdollista pitää kupin mukana jopa 592 millilitraa (ml) kahvia. Jos ohjelmoija lisää uuden kuppikoon tajuamatta, että käytät 500 ml osoittaaksesi, että kuppi on pestävä, on todennäköistä, että vika otetaan käyttöön. Jos virtuaalisen kahvilasi asiakas osti 20 unssin kupin ja otti sitten ison 92 ml: n annoksen, hänellä olisi sitten kuppiin jäljellä tarkalleen 500 ml. Asiakas olisi järkyttynyt ja tyytymätön, kun vain 92 ml juomisen jälkeen kuppi katosi kädestään ja ilmestyi pesualtaaseen. Ja vaikka muutoksen tekevä ohjelmoija huomaisi, että käytit erityistä arvoa, pesemättömälle attribuutille olisi valittava toinen erityinen arvo.

Parempi lähestymistapa tähän tilanteeseen on saada erillinen kenttä erillisen määritteen mallintamiseksi:

// Lähdepaketissa tiedostokentissä / ex2 / CoffeeCup.java-luokka CoffeeCup {private int innerCoffee; yksityiset loogiset tarpeetPesu; public boolean isReadyForNextUse () {// Jos kahvikuppi ei ole pesty, se // ei ole valmis seuraavaa käyttöä varten return! needsWashing; } public void setCustomerDone () {needsWashing = true; // ...} public void wash () {needsWashing = false; // ...} // ...} 

Tässä sisäinen kahvi kenttää käytetään vain mallinnamaan kahvimäärää kuppi-määritteessä. Kuppi tarvitsee pestä -ominaisuuden mallintaa needsPesu ala. Tämä kaavio on helpommin ymmärrettävissä kuin edellinen järjestelmä, jossa käytettiin erityistä arvoa sisäinen kahvi eikä estäisi jotakuta laajentamasta enimmäisarvoa sisäinen kahvi.

Vakioiden käyttö

Toinen nyrkkisääntö, jota on noudatettava kenttien luomisessa, on käyttää vakioita (staattisia lopullisia muuttujia) vakioarvoille, jotka välitetään, palautetaan tai joita käytetään menetelmissä. Jos menetelmä odottaa yhtä lopullisesta vakioarvojen joukosta yhdessä sen parametreista, vakioiden määritteleminen auttaa tekemään asiakasohjelmoijille selvemmäksi, mitä kyseisessä parametrissa on välitettävä. Samoin, jos menetelmä palauttaa yhden rajallisesta arvojoukosta, vakioiden ilmoittaminen tekee asiakasohjelmoijille selvemmäksi, mitä odottaa lähtöä. Esimerkiksi tämä on helpompi ymmärtää:

jos (cup.getSize () == Kahvikuppi TALL) {} 

kuin on ymmärtää tämä:

jos (cup.getSize () == 1) {} 

Sinun tulisi myös määritellä vakiot sisäiseen käyttöön luokan menetelmillä - vaikka niitä ei käytettäisikään luokan ulkopuolella -, jotta ne olisi helpompi ymmärtää ja muuttaa. Vakioiden käyttö tekee koodista joustavampaa. Jos huomaat, että olet laskenut arvon väärin etkä käyttänyt vakiota, joudut käymään läpi koodisi ja muuttamaan jokaista kovakoodatun arvon esiintymää. Jos kuitenkin käytit vakiota, sinun on muutettava sitä vain siellä, missä se on määritelty vakiona.

Vakiot ja Java-kääntäjä

Hyödyllinen tieto Java-kääntäjästä on, että se kohtelee staattisia lopullisia kenttiä (vakioita) eri tavalla kuin muunlaisia ​​kenttiä. Viitteet staattisiin lopullisiin muuttujiin, jotka on alustettu kääntöaikavakioon, ratkaistaan ​​käännösaikana vakioarvon paikalliseen kopioon. Tämä pätee kaikkien primitiivityyppisten ja -tyyppisten vakioiden osalta java.lang.String.

Normaalisti, kun luokkasi viittaa toiseen luokkaan - sanokaa, luokka java.lang.Math - Java-kääntäjä sijoittaa symbolisia viittauksia luokkaan Matematiikka luokan luokkatiedostoon. Esimerkiksi, jos luokkasi menetelmä käyttää Math.sin (), luokkatiedostosi sisältää kaksi symbolista viittausta Matematiikka:

  • Yksi symbolinen viittaus luokkaan Matematiikka
  • Yksi symbolinen viittaus Matematiikkaon synti() menetelmä

Suorita luokkasi koodi, johon viitataan Math.sin (), JVM: n on kuormitettava luokka Matematiikka symbolisten viitteiden ratkaisemiseksi.

Jos toisaalta koodisi viittasi vain staattiseen lopulliseen luokan muuttujaan PI ilmoitettu luokassa Matematiikka, Java-kääntäjä ei aseta mitään symbolista viittausta Matematiikka luokan luokkatiedostossa. Sen sijaan se yksinkertaisesti sijoittaa kopion kirjaimellisesta arvosta Math.PI luokan luokkatiedostoon. Suorita luokan käyttämä koodi, joka käyttää Math.PI vakiona, JVM: n ei tarvitse ladata luokkaa Matematiikka.

Java-kääntäjän tämän ominaisuuden tulos on se, että JVM: n ei tarvitse työskennellä kovemmin vakioiden käyttämiseksi kuin literaalien käyttämisessä. Vakioiden suosiminen literaaleihin on yksi harvoista suunnitteluohjeista, joka parantaa ohjelman joustavuutta vaarantamatta ohjelman suorituskyvyn heikkenemistä.

Kolme erilaista menetelmää

Tämän artikkelin loppuosa käsittelee menetelmien suunnittelutekniikoita, jotka koskevat menetelmän käyttämiä tai muokkaamia tietoja. Tässä yhteydessä haluaisin tunnistaa ja nimetä Java-ohjelmien kolme perustyyppiä: hyödyllisyysmenetelmä tilanäkymämenetelmä, ja tilanvaihtomenetelmä.

Hyödyllisyysmenetelmä

Apuohjelma-menetelmä on luokkamenetelmä, joka ei käytä tai muokkaa luokansa tilaa (luokan muuttujia). Tällainen menetelmä tarjoaa yksinkertaisesti hyödyllisen palvelun, joka liittyy sen objektiluokkaan.

Joitakin esimerkkejä Java-sovellusliittymän hyödyllisyysmenetelmistä ovat:

  • (Luokassa Kokonaisluku) julkinen staattinen int toString (int i) - palauttaa uuden Merkkijono objekti, joka edustaa määritettyä kokonaislukua radiksissa 10
  • (Luokassa Matematiikka) julkinen staattinen natiivi kaksinkertainen cos (kaksinkertainen a) - palauttaa kulman trigonometrisen kosinin

Tilanäkymämenetelmä

Tilanäkymämenetelmä on luokka- tai instanssimenetelmä, joka palauttaa osan näkymästä luokan tai objektin sisäisestä tilasta muuttamatta kyseistä tilaa. (Tällainen menetelmä jättää räikeästi huomiotta Heisenbergin epävarmuusperiaatteen - katso Resurssit, jos tarvitset päivitystä tälle periaatteelle.) Tilanäkymämenetelmä voi yksinkertaisesti palauttaa luokan tai esiintymämuuttujan arvon tai palauttaa arvon, joka on laskettu useita luokka- tai instanssimuuttujia.

Joitakin esimerkkejä Java-sovellusliittymän tilanäkymämenetelmistä ovat:

  • (Luokassa Esine) public String toString () - palauttaa objektin merkkijonon
  • (Luokassa Kokonaisluku) julkisen tavun tavuarvo () - palauttaa arvon Kokonaisluku esine tavuna
  • (Luokassa Merkkijono) public int indexOf (int ch) - palauttaa indeksin määritetyn merkin ensimmäisen esiintymisen merkkijonossa

Tilanvaihtomenetelmä

Tilamuutosmenetelmä on menetelmä, joka voi muuttaa sen luokan tilan, jossa menetelmä on ilmoitettu, tai jos esiintymämenetelmänä, objektin, johon sitä kutsutaan. Kun tilanvaihtomenetelmää käytetään, se edustaa "tapahtumaa" luokalle tai objektille. Menetelmän koodi "käsittelee" tapahtumaa, mikä voi muuttaa luokan tai objektin tilaa.

Joitakin esimerkkejä Java-sovellusliittymän tilanvaihtomenetelmistä ovat:

  • (Luokassa StringBuffer) julkinen StringBuffer-liite (int i) - liittää merkkijonon merkkijonon int argumentti StringBuffer
  • (Luokassa Hashtable) julkinen synkronoitu void clear () - tyhjentää Hashtable niin että se ei sisällä avaimia
  • (Luokassa Vektori) julkinen lopullinen synkronoitu void addElement (Object obj) - lisää määritetyn komponentin Vektori, lisäämällä sen kokoa yhdellä

Menetelmäkytkennän minimointi

Näiden apuohjelmien, tilanäkymän ja tilanmuutosmenetelmien määritelmien avulla olet valmis keskustelemaan menetelmäkytkennästä.

Suunnitellessasi menetelmiä yhden tavoitteistasi tulisi olla minimointi kytkentä - menetelmän ja sen ympäristön (muut menetelmät, objektit ja luokat) keskinäisen riippuvuuden aste. Mitä vähemmän kytkentää menetelmän ja sen ympäristön välillä on, sitä riippumattomampi menetelmä on ja sitä joustavampi rakenne on.

Menetelmät tiedonmuuntajina

Yhdistämisen ymmärtäminen auttaa ajattelemaan menetelmiä puhtaasti datan muuntajina. Menetelmät hyväksyvät tiedot syötteeksi, suorittavat toimenpiteitä kyseisille tiedoille ja tuottavat tietoja tuotoksena. Menetelmän kytkentäaste määräytyy ensisijaisesti sen mukaan, mihin se saa syöttötiedonsa ja mihin laittaa lähtötiedonsa.

Kuvassa 1 on graafinen kuvaus menetelmästä tiedonsiirtona: Datavuokaavio strukturoidusta (ei olio-orientoidusta) suunnittelusta.

Tulo ja lähtö

Javan menetelmä voi saada tulotietoja monista lähteistä:

  • Se voi vaatia, että soittaja määrittää syöttötiedonsa parametreiksi, kun sitä kutsutaan
  • Se voi napata tietoja mistä tahansa käytettävissä olevasta luokan muuttujasta, kuten luokan omasta luokan muuttujasta tai mistä tahansa toisen luokan käytettävissä olevasta luokan muuttujasta
  • Jos kyseessä on ilmentymämenetelmä, se voi napata ilmentymämuuttujia objektista, johon se on kutsuttu

Samoin menetelmä voi ilmaista tuotoksensa monissa paikoissa:

  • Se voi palauttaa arvon, joko primitiivisen tyypin tai objektiviitteen
  • Se voi muuttaa objekteja, joihin viitataan parametreina
  • Se voi muuttaa minkä tahansa oman luokansa luokan muuttujia tai minkä tahansa toisen luokan käytettävissä olevia luokan muuttujia
  • Jos kyseessä on instanssimenetelmä, se voi muuttaa minkä tahansa objektin ilmentymämuuttujia, joihin sitä käytettiin
  • Se voi aiheuttaa poikkeuksen

Huomaa, että parametrit, palautusarvot ja heitetyt poikkeukset eivät ole ainoat menetelmien tulot ja lähdöt, jotka on mainittu yllä olevissa luetteloissa. Ilmentymän ja luokan muuttujia käsitellään myös syötteenä ja tuotoksena. Tämä saattaa tuntua ei-intuitiiviselta olio-suuntautuneesta näkökulmasta, koska Java-ilmentymien ja luokkien muuttujien käyttö on "automaattista" (sinun ei tarvitse siirtää mitään nimenomaisesti menetelmälle). Kun yrität mitata menetelmän kytkentää, sinun on kuitenkin tarkasteltava käytetyn ja koodin muokkaaman datan tyyppiä ja määrää riippumatta siitä, oliko koodin pääsy kyseisiin tietoihin "automaattinen" vai ei.

Vähintään kytketyt hyödyllisyysmenetelmät

Pienin yhdistetty menetelmä, joka on mahdollista Java-tilassa, on apuohjelma, joka:

  1. Ottaa syötteen vain sen parametreista
  2. Ilmaisee tuotoksensa vain parametrien tai palautusarvon kautta (tai heittämällä poikkeuksen)
  3. Hyväksyy syötteenä vain tiedot, joita menetelmä todella tarvitsee
  4. Palauttaa vain tuotoksena menetelmän tosiasiallisesti tuottamat tiedot

Hyvä apuohjelma

Esimerkiksi menetelmä convertOzToMl () alla esitetty hyväksyy int sen ainoana syötteenä ja palauttaa int ainoana tuotoksena:

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