Programiranje

Zakaj so getter in setter metode zlobne

Nisem nameraval začeti serije "je zlo", vendar me je več bralcev prosilo, naj pojasnim, zakaj sem omenil metode get / set v prejšnjem mesecu v rubriki "Zakaj razširja je zlo".

Čeprav so metode pridobivanja / nastavljanja v Javi običajne, niso posebej objektno usmerjene (OO). Dejansko lahko poškodujejo vzdrževanje vaše kode. Poleg tega je prisotnost številnih metod pridobivanja in nastavljanja rdeča zastavica, da program ni nujno dobro zasnovan z vidika OO.

Ta članek pojasnjuje, zakaj ne bi smeli uporabljati geterjev in nastaviteljev (in kdaj jih lahko uporabite), ter predlaga metodologijo oblikovanja, ki vam bo pomagala, da se izognete miselnosti geterja / seterja.

O naravi oblikovanja

Preden začnem z drugim oblikovalskim stolpcem (z izzivalnim naslovom, nič manj), želim pojasniti nekaj stvari.

Nekoliko me je razburilo nekaj komentarjev bralcev, ki so nastali v prejšnjem mesecu v rubriki »Zakaj se razširi zlo« (glej Talkback na zadnji strani članka). Nekateri so verjeli, da trdim, da je objektna usmerjenost slaba samo zato, ker podaljša ima težave, kot da sta oba koncepta enakovredna. To zagotovo ni tisto, kar jaz mislil Rekel sem, zato naj pojasnim nekaj meta vprašanj.

Ta stolpec in prejšnji mesec govori o oblikovanju. Oblikovanje je po svoji naravi vrsta kompromisov. Vsaka izbira ima dobro in slabo stran, vi pa se odločite v okviru splošnih meril, ki jih določa potreba. Dobro in slabo pa nista absolutna. Dobra odločitev v enem kontekstu je morda slaba v drugem.

Če ne razumete obeh strani vprašanja, ne morete pametno izbrati; pravzaprav, če ne razumete vseh posledic svojih dejanj, sploh ne načrtujete. Spotikaš se v temi. Ni naključje, da je vsako poglavje v Gang of Four's Vzorci oblikovanja knjiga vsebuje odsek "Posledice", ki opisuje, kdaj in zakaj je uporaba vzorca neprimerna.

Navedba, da imajo nekatere jezikovne funkcije ali običajni programski idiom (na primer accessors) težave, ni enaka reči, da jih nikakor ne smete uporabljati. In samo zato, ker se značilnost ali frazem pogosto uporablja, še ne pomeni vas bi morali uporabite ga bodisi. Neobveščeni programerji pišejo številne programe in preprosto zaposlitev v podjetju Sun Microsystems ali Microsoft ne čarobno izboljša nekoga pri programiranju ali oblikovanju. Paketi Java vsebujejo veliko odlične kode. Obstajajo pa tudi deli te kode. Prepričan sem, da je avtorjem nerodno priznati, da so napisali.

Trženje ali politične spodbude pogosto potiskajo oblikovalske idiome. Včasih se programerji sprejemajo slabe odločitve, vendar podjetja želijo promovirati, kaj tehnologija zmore, zato ne poudarjajo, da je način, na katerega to počnete, manj kot idealen. Slabo situacijo izkoristijo najbolje. Posledično ravnate neodgovorno, ko sprejmete katero koli prakso programiranja, preprosto zato, ker "tako bi morali delati stvari." Številni neuspešni projekti Enterprise JavaBeans (EJB) dokazujejo to načelo. Tehnologija, ki temelji na EJB, je ob primerni uporabi odlična tehnologija, ki pa lahko ob neprimerni uporabi dobesedno uniči podjetje.

Moja poanta je, da ne smete programirati na slepo. Razumeti morate opustošenje, ki ga lahko povzroči funkcija ali frazem. S tem ste v veliko boljšem položaju, da se odločite, ali želite uporabiti to funkcijo ali idiom. Vaše odločitve naj bodo tako informirane kot pragmatične. Namen teh člankov je, da vam pomagajo pri programiranju z odprtimi očmi.

Odvzem podatkov

Temeljni predpis sistemov OO je, da objekt ne sme razkriti nobenih podrobnosti o njegovi izvedbi. Na ta način lahko spremenite izvedbo, ne da bi spremenili kodo, ki uporablja objekt. Iz tega sledi, da se v sistemih OO izogibajte funkcijam getter in setter, saj večinoma omogočajo dostop do podrobnosti izvedbe.

Če želite ugotoviti, zakaj, upoštevajte, da je na klicno enoto morda 1000 klicev getX () v vašem programu in vsak klic predpostavlja, da je vrnjena vrednost določene vrste. Lahko shranite getX ()na primer vrnjena vrednost v lokalni spremenljivki in ta vrsta spremenljivke se mora ujemati s vrnjeno vrednostjo. Če morate način izvedbe predmeta spremeniti tako, da se spremeni tip X, ste v globokih težavah.

Če bi bil X int, zdaj pa mora biti dolga, boste dobili 1000 napak pri prevajanju. Če napako odpravite tako, da vrnete vrnjeno vrednost v int, bo koda prevedena čisto, vendar ne bo delovala. (Vrnjena vrednost je lahko okrnjena.) Za kompenzacijo spremembe morate spremeniti kodo, ki obdaja vsakega od teh 1.000 klicev. Vsekakor si ne želim delati toliko.

Eno od osnovnih načel sistemov OO je abstrakcija podatkov. Način, na katerega objekt izvaja obdelovalec sporočil, morate popolnoma skriti pred ostalim programom. To je eden od razlogov, zakaj bi morale biti vse spremenljivke primerka (nestalna polja razreda) zasebno.

Če naredite spremenljivko primerka javnosti, potem ne morete spremeniti polja, saj se razred sčasoma razvija, ker bi zlomili zunanjo kodo, ki uporablja polje. Ne želite iskati 1.000 uporab razreda samo zato, ker ga spremenite.

To načelo skrivanja izvedbe vodi do dobrega preskusa kakovosti sistema OO: ali lahko bistveno spremenite definicijo razreda - celo celo celo zavržete in jo zamenjate s povsem drugačno izvedbo - ne da bi pri tem vplivali na kodo, ki to uporablja predmeti razreda? Tovrstna modularizacija je osrednja predpostavka usmerjenosti objekta in olajša vzdrževanje. Brez skrivanja izvedbe je malo smisla uporabljati druge funkcije OO.

Metode pridobivanja in nastavitve (znane tudi kot accessors) so nevarne iz istega razloga javnosti polja so nevarna: zagotavljajo zunanji dostop do podrobnosti izvedbe. Kaj če morate spremeniti vrsto dostopa do polja? Spremeniti morate tudi vrsto vračila dostopnika. To povratno vrednost uporabljate na številnih mestih, zato morate spremeniti tudi vso to kodo. Učinke spremembe želim omejiti na eno definicijo razreda. Nočem, da se vmešajo v celoten program.

Ker dostopniki kršijo načelo enkapsulacije, lahko utemeljeno trdite, da sistem, ki močno ali neprimerno uporablja dostopnike, preprosto ni objektno usmerjen. Če greste skozi postopek oblikovanja, v nasprotju s samo kodiranjem v svojem programu skoraj ne boste našli nobenega dodatka. Postopek je pomemben. O tem vprašanju moram povedati več na koncu članka.

Pomanjkanje getter / setter metod ne pomeni, da nekateri podatki ne tečejo skozi sistem. Kljub temu je najbolje čim bolj zmanjšati pretok podatkov. Moja izkušnja je, da je vzdrževalnost obratno sorazmerna s količino podatkov, ki se premikajo med predmeti. Čeprav morda še ne vidite, kako, lahko dejansko odpravite večino tega prenosa podatkov.

Če skrbno načrtujete in se osredotočate na to, kaj morate storiti, namesto na to, kako to storite, v svojem programu odpravite veliko večino getter / setter metod. Ne zahtevajte informacij, ki jih potrebujete za delo; prosite objekt, ki ima informacije, da opravi delo namesto vas. Večina pristopov se znajde v kodi, ker oblikovalci niso razmišljali o dinamičnem modelu: izvajalnih objektih in sporočilih, ki si jih medsebojno pošiljajo. Začnejo (nepravilno) z načrtovanjem hierarhije razredov, nato pa te razrede poskušajo usmeriti v dinamični model. Ta pristop nikoli ne deluje. Če želite zgraditi statični model, morate odkriti odnose med razredi in ti odnosi natančno ustrezajo toku sporočil. Povezava obstaja med dvema razredoma le, če predmeti enega razreda pošiljajo sporočila objektom drugega razreda. Glavni namen statičnega modela je zajeti te informacije o povezavi, ko dinamično modelirate.

Brez jasno definiranega dinamičnega modela samo ugibate, kako boste uporabili predmete razreda. Posledično se v modelu pogosto končajo metode dostopa, ker morate zagotoviti čim več dostopa, saj ne morete predvideti, ali ga boste potrebovali ali ne. Tovrstna strategija načrtovanja z ugibanjem je v najboljšem primeru neučinkovita. Zapravljate čas s pisanjem neuporabnih metod (ali dodajanjem nepotrebnih zmožnosti učilnicam).

Pripomočki se na koncu v obliki končajo tudi s silo navade. Ko proceduralni programerji sprejmejo Javo, običajno začnejo z gradnjo znane kode. Procesni jeziki nimajo predavanj, imajo pa C strukt (pomislite: razred brez metod). Potem se zdi naravno, da posnemamo a strukt z gradnjo definicij razredov tako rekoč brez metod in nič drugega kot javnosti polja. Ti proceduralni programerji so nekje prebrali, da bi morala biti polja zasebnovendar pa naredijo polja zasebno in oskrbe javnosti metode dostopa. A dostop javnosti so le zapletli. Zagotovo niso naredili sistemsko objektno usmerjenega.

Nariši se

Ena izmed posledic polne enkapsulacije je v izdelavi uporabniškega vmesnika (UI). Če ne morete uporabljati pristopov, ne morete poklicati razreda graditelja uporabniškega vmesnika a getAttribute () metoda. Namesto tega imajo razredi elemente kot nariši se (...) metode.

A getIdentity () metoda lahko deluje tudi seveda pod pogojem, da vrne objekt, ki izvaja Identiteta vmesnik. Ta vmesnik mora vsebovati a nariši se () (ali daj mi-a-JComponent-that-predstavlja-vašo-identiteto). Pa čeprav getIdentity začne se z "get", to ni accessor, ker ne vrne samo polja. Vrne zapleten objekt z razumnim vedenjem. Tudi ko imam Identiteta predmet, še vedno ne vem, kako je identiteta predstavljena znotraj.

Seveda, a nariši se () strategija pomeni, da sem (dahnem!) v poslovno logiko vnesel kodo uporabniškega vmesnika. Razmislite, kaj se zgodi, ko se zahteve uporabniškega vmesnika spremenijo. Recimo, da želim atribut predstaviti na povsem drugačen način. Danes je "identiteta" ime; jutri je to ime in osebna številka; naslednji dan je to ime, ID številka in slika. Obseg teh sprememb omejim na eno mesto v kodi. Če imam daj miJComponent-that-predstavlja-vašo-identiteto, potem sem izoliral način predstavitve identitet od ostalega sistema.

Upoštevajte, da v poslovno logiko dejansko nisem vnesel nobene kode uporabniškega vmesnika. Plast uporabniškega vmesnika sem napisal v smislu AWT (Abstract Window Toolkit) ali Swing, ki sta oba abstraktna sloja. Dejanska koda uporabniškega vmesnika je v izvedbi AWT / Swing. V tem je bistvo abstraktnega sloja - da poslovno logiko izolirate od mehanike podsistema. Z lahkoto lahko priključim na drugo grafično okolje, ne da bi spremenil kodo, zato je edina težava malo nereda. To nered lahko enostavno odpravite s premikanjem celotne kode uporabniškega vmesnika v notranji razred (ali z uporabo vzorca oblikovanja fasade).

JavaBeans

Lahko bi ugovarjali, če bi rekli: "Kaj pa JavaBeans?" Kaj pa oni? Zagotovo lahko JavaBeans zgradite brez pridobivalcev in nastaviteljev. The BeanCustomizer, BeanInfo, in BeanDescriptor vsi razredi obstajajo ravno v ta namen. Oblikovalci specifikacij JavaBean so v sliko vrgli idiom getter / setter, ker so menili, da bo to enostaven način za hitro izdelavo fižola - nekaj, kar lahko storite, medtem ko se učite, kako to storiti pravilno. Tega žal ni storil nihče.

Dostopniki so bili ustvarjeni zgolj kot način označevanja določenih lastnosti, tako da jih lahko prepozna program U-build-a ali enakovreden program. Teh metod naj ne bi klicali sami. Obstajajo za uporabo avtomatiziranega orodja. To orodje uporablja API-je introspekcije v Razred razreda, da poišče metode in iz imen metod ekstrapolira obstoj določenih lastnosti. V praksi se ta idiom, ki temelji na introspekciji, ni izšel. Koda je postala preveč zapletena in postopkovna. Programerji, ki ne razumejo odvzema podatkov, dejansko pokličejo dostopnike, zato je koda manj vzdržna. Iz tega razloga bo funkcija metapodatkov vključena v Javo 1.5 (predvidoma sredi leta 2004). Torej namesto:

zasebna int lastnina; public int getProperty () {return lastnost; } javna void setProperty (int value} {lastnost = vrednost;} 

Uporabili boste lahko nekaj takega:

zasebna lastnina @property int; 

Orodje za izdelavo uporabniškega vmesnika ali enakovredno orodje bo za iskanje lastnosti uporabljalo API-je za introspekcijo, namesto da preuči imena metod in iz imena sklepa na obstoj lastnosti. Zato noben izvajalec dostopa ne poškoduje vaše kode.

Kdaj je dodatek v redu?

Prvič, kot sem že omenil, je v redu, da metoda vrne objekt v smislu vmesnika, ki ga objekt izvaja, ker vas ta vmesnik izolira od sprememb izvedbenega razreda. Ta vrsta metode (ki vrne sklic na vmesnik) v resnici ni "pridobitelj" v smislu metode, ki samo omogoča dostop do polja. Če spremenite ponudnikovo interno izvedbo, samo spremenite definicijo vrnjenega predmeta, da bo ustrezal spremembam. Zunanjo kodo, ki uporablja predmet, še vedno ščitite prek vmesnika.

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