Programmēšana

Kāpēc getter un setter metodes ir ļaunas

Es nedomāju sākt sēriju "ir ļauns", taču vairāki lasītāji man lūdza paskaidrot, kāpēc es minēju, ka jums vajadzētu izvairīties no get / set metodēm pagājušā mēneša slejā "Kāpēc paplašina ir ļauns".

Lai gan getter / setter metodes Java ir izplatītas, tās nav īpaši orientētas uz objektu (OO). Patiesībā tie var sabojāt koda uzturēšanu. Turklāt daudzu getter un setter metožu klātbūtne ir sarkans karodziņš, ka programma ne vienmēr ir labi izstrādāta no OO viedokļa.

Šajā rakstā ir paskaidrots, kāpēc nevajadzētu izmantot getters un seterus (un kad jūs tos varat izmantot), un tiek piedāvāta dizaina metodika, kas palīdzēs jums izkļūt no getter / setter mentalitātes.

Par dizaina būtību

Pirms es sāku nokļūt citā ar dizainu saistītā slejā (ar provokatīvu nosaukumu, ne mazāk), es vēlos precizēt dažas lietas.

Mani satrieca daži lasītāju komentāri, kas izrietēja no pagājušā mēneša slejas "Kāpēc paplašina, ir ļauns" (skat. Talkback raksta pēdējā lappusē). Daži cilvēki uzskatīja, ka es apgalvoju, ka objekta orientācija ir slikta tikai tāpēc, ka pagarina ir problēmas, it kā abi jēdzieni būtu līdzvērtīgi. Tas noteikti nav tas, ko es nodomāju Es teicu, tāpēc ļaujiet man precizēt dažus meta jautājumus.

Šī sleja un pagājušā mēneša raksts ir par dizainu. Dizains pēc būtības ir virkne kompromisu. Katrai izvēlei ir labā un sliktā puse, un jūs to izdarāt vispārējo kritēriju kontekstā, ko nosaka nepieciešamība. Labs un slikts tomēr nav absolūts. Labs lēmums vienā kontekstā var būt slikts citā.

Ja jūs nesaprotat jautājuma abas puses, jūs nevarat izdarīt saprātīgu izvēli; Patiesībā, ja jūs nesaprotat visus savas darbības atzarus, jūs vispār neveidojat dizainu. Jūs klupat tumsā. Tā nav nejaušība, ka katra nodaļa Četru bandā Dizaina modeļi grāmatā ir sadaļa "Sekas", kurā aprakstīts, kad un kāpēc modeļa lietošana nav piemērota.

Norādījums, ka kādai valodas iezīmei vai izplatītai programmēšanas idiomai (piemēram, piekļuvējiem) ir problēmas, nav tas pats, kas teikt, ka nekādā gadījumā tos nekad nevajadzētu lietot. Un tas, ka parasti tiek izmantota kāda iezīme vai idioma, nenozīmē jūs vajadzētu izmantojiet arī to. Neinformēti programmētāji raksta daudzas programmas, un vienkārši tas, ka strādā Sun Microsystems vai Microsoft, maģiski neuzlabo kāda programmēšanas vai dizaina spējas. Java paketēs ir daudz lieliska koda. Bet ir arī dažas šī koda daļas, es esmu pārliecināts, ka autori ir neērti atzīt, ka viņi ir uzrakstījuši.

Tādā pašā veidā mārketinga vai politiskie stimuli bieži mudina dizaina idiomas. Dažreiz programmētāji pieņem sliktus lēmumus, bet uzņēmumi vēlas popularizēt tehnoloģiju iespējas, tāpēc viņi uzsver, ka veids, kā jūs to darāt, ir mazāks nekā ideāls. Viņi sliktajā situācijā izmanto vislabāko. Līdz ar to jūs rīkojaties bezatbildīgi, pieņemot jebkādu programmēšanas praksi tikai tāpēc, ka "tā jums vajadzētu darīt lietas". Daudzi neveiksmīgi Enterprise JavaBeans (EJB) projekti pierāda šo principu. Uz EJB balstīta tehnoloģija ir lieliska tehnoloģija, ja to lieto atbilstoši, taču tā var burtiski sagraut uzņēmumu, ja to izmanto neatbilstoši.

Mans viedoklis ir tāds, ka jums nevajadzētu programmēt akli. Jums jāsaprot, kādu postu var izraisīt kāda iezīme vai idioma. To darot, jums ir daudz labākas iespējas izlemt, vai jums jāizmanto šī funkcija vai idioma. Jūsu izvēlei jābūt gan informētai, gan pragmatiskai. Šo rakstu mērķis ir palīdzēt jums atvērt programmēšanu ar atvērtām acīm.

Datu ieguve

OO sistēmu pamatnoteikums ir tāds, ka objektam nevajadzētu atklāt nevienu no tā ieviešanas detaļām. Tādā veidā jūs varat mainīt ieviešanu, nemainot kodu, kas izmanto objektu. No tā izriet, ka OO sistēmās jums vajadzētu izvairīties no uzlabošanas un iestatīšanas funkcijām, jo ​​tās galvenokārt nodrošina piekļuvi ieviešanas detaļām.

Lai uzzinātu, kāpēc, ņemiet vērā, ka varētu būt 1000 zvanu uz a getX () metodi, un katrs zvans pieņem, ka atgriešanās vērtība ir noteikta veida. Jūs varētu uzglabāt getX ()atgriešanās vērtībai, piemēram, lokālajā mainīgajā, un šim mainīgā tipam jāatbilst atgriešanās vērtības tipam. Ja jums ir jāmaina objekta ieviešanas veids, lai mainītos X tips, jūs esat nonācis pamatīgās nepatikšanās.

Ja X būtu int, bet tagad tam jābūt ilgi, jūs saņemsiet 1000 kompilēšanas kļūdu. Ja nepareizi novēršat problēmu, atdodot atgriešanās vērtību uz int, kods tiks kompilēts tīri, taču tas nedarbosies. (Atgriešanās vērtība var būt saīsināta.) Lai kompensētu izmaiņas, jums ir jāmaina kods, kas ap katru no šiem 1000 zvaniem. Es noteikti nevēlos darīt tik daudz darba.

Viens OO sistēmu pamatprincips ir datu abstrakcija. Jums vajadzētu pilnībā paslēpt veidu, kādā objekts īsteno ziņojumu apstrādātāju, no pārējās programmas. Tas ir viens iemesls, kāpēc visiem jūsu instances mainīgajiem (klases nemainīgiem laukiem) vajadzētu būt Privāts.

Ja izveidojat instances mainīgo publiski, tad jūs nevarat mainīt lauku, kad klase laika gaitā attīstās, jo jūs izjauktu ārējo kodu, kas izmanto lauku. Jūs nevēlaties meklēt 1000 klases lietojumus tikai tāpēc, ka maināt šo klasi.

Šis ieviešanas slēpšanas princips nodrošina labu OO sistēmas skābes pārbaudi: vai jūs varat veikt lielas izmaiņas klases definīcijā - pat izmest visu un aizstāt to ar pilnīgi atšķirīgu ieviešanu - neietekmējot nevienu kodu, kas to izmanto klases objekti? Šāda veida modulēšana ir objekta orientācijas galvenā priekšnoteikums, kas ievērojami atvieglo apkopi. Neslēpjot ieviešanu, nav lielas jēgas izmantot citas OO funkcijas.

Labieru un seteru metodes (sauktas arī par piekļuvēm) ir bīstamas tā paša iemesla dēļ publiski lauki ir bīstami: tie nodrošina ārēju piekļuvi detaļām par ieviešanu. Ko darīt, ja jāmaina piekļūtā lauka tips? Jums arī jāmaina piekļuves atgriešanas veids. Jūs izmantojat šo atgriešanās vērtību daudzās vietās, tāpēc jums arī jāmaina viss šis kods. Es vēlos ierobežot izmaiņu ietekmi uz vienu klases definīciju. Es negribu, lai viņi viļņotos visā programmā.

Tā kā piekļuves sniedzēji pārkāpj iekapsulēšanas principu, varat pamatoti apgalvot, ka sistēma, kas intensīvi vai neatbilstoši izmanto piekļuves, vienkārši nav orientēta uz objektu. Ja jūs veicat projektēšanas procesu, nevis tikai kodēšanu, jūs savā programmā atradīsit gandrīz nevienu piekļuvi. Process ir svarīgs. Man ir vairāk jāpasaka par šo jautājumu raksta beigās.

Getter / setter metožu trūkums nenozīmē, ka daži dati neplūst caur sistēmu. Neskatoties uz to, vislabāk ir maksimāli samazināt datu kustību. Mana pieredze ir tāda, ka uzturamība ir apgriezti proporcionāla datu daudzumam, kas pārvietojas starp objektiem. Lai gan jūs, iespējams, vēl neredzat, kā to izdarīt, jūs faktiski varat novērst lielāko daļu šīs datu kustības.

Rūpīgi izstrādājot un koncentrējoties uz to, kas jums jādara, nevis uz to, kā jūs to darīsit, jūs savā programmā izslēdzat lielāko daļu getter / setter metožu. Neprasiet informāciju, kas jums nepieciešama darba veikšanai; palūdziet objektam, kuram ir informācija, veikt darbu jūsu vietā. Lielākā daļa piekļuvju atrod kodu, jo dizaineri nedomāja par dinamisko modeli: izpildlaika objektiem un ziņojumiem, kurus viņi sūta viens otram, lai veiktu darbu. Viņi sāk (nepareizi), izstrādājot klases hierarhiju, un pēc tam mēģina šīs klases ievietot dinamiskajā modelī. Šī pieeja nekad nedarbojas. Lai izveidotu statisku modeli, jums jāatklāj attiecības starp klasēm, un šīs attiecības precīzi atbilst ziņojumu plūsmai. Asociācija pastāv starp divām klasēm tikai tad, kad vienas klases objekti sūta ziņojumus otras klases objektiem. Statiskā modeļa galvenais mērķis ir iegūt šo asociācijas informāciju, dinamiski modelējot.

Bez skaidri definēta dinamiskā modeļa jūs tikai uzminējat, kā izmantosiet klases objektus. Līdz ar to piekļuves metodes bieži nonāk modelī, jo jums jānodrošina pēc iespējas vairāk piekļuves, jo nevarat paredzēt, vai tā jums būs nepieciešama. Šāda veida stratēģija pēc uzminēšanas labākajā gadījumā ir neefektīva. Jūs tērējat laiku, rakstot bezjēdzīgas metodes (vai pievienojot nevajadzīgas iespējas nodarbībām).

Piekļuves arī nonāk dizainā ar ieraduma spēku. Kad procesuālie programmētāji pieņem Java, viņi parasti sāk veidot pazīstamu kodu. Procesuālajām valodām nav klases, bet tām ir C struktur (domāju: klase bez metodēm). Tad šķiet dabiski atdarināt a struktur veidojot klases definīcijas praktiski bez metodēm un tikai publiski lauki. Šie procesuālie programmētāji kaut kur nolasīja, ka laukiem jābūt Privāts, tomēr tāpēc viņi veic laukus Privāts un piegādi publiski piekļuves metodes. Bet tie ir tikai sarežģījuši sabiedrības piekļuvi. Viņi noteikti nav padarījuši sistēmu par objektu orientētu.

Uzzīmē pats

Viens lauka iekapsulēšanas atzars ir lietotāja saskarnes (UI) konstrukcijā. Ja nevarat izmantot piederumus, nevarat UI veidotāju klasē izsaukt a getAttribute () metodi. Tā vietā klasēs ir tādi elementi kā izdarīt pats (...) metodes.

A getIdentity () metode, protams, var darboties arī ar nosacījumu, ka tā atgriež objektu, kas realizē Identitāte interfeiss. Šajā saskarnē jāiekļauj a izdarīt pats () (vai dod-man-a-JKomponents- kas pārstāv jūsu identitāti) metodi. Lai arī getIdentity sākas ar "get", tas nav piekļuvējs, jo tas neatgriež tikai lauku. Tas atgriež sarežģītu objektu, kuram ir saprātīga izturēšanās. Pat tad, kad man ir Identitāte objekts, man joprojām nav ne jausmas, kā identitāte tiek pārstāvēta iekšēji.

Protams, a izdarīt pats () stratēģija nozīmē, ka es (uzpūtīšu!) Ievietoju lietotāja saskarnes kodu biznesa loģikā. Apsveriet, kas notiek, mainoties lietotāja saskarnes prasībām. Pieņemsim, ka es vēlos atribūtu attēlot pilnīgi citādi. Mūsdienās "identitāte" ir vārds; rīt tas ir vārds un ID numurs; nākamajā dienā pēc tam tas ir vārds, ID numurs un attēls. Es ierobežoju šo izmaiņu darbības jomu tikai vienā vietā kodā. Ja man ir dot-man-a-JKomponents- kas pārstāv jūsu identitātes klasi, tad es esmu izolējis veidu, kā identitātes tiek attēlotas no pārējās sistēmas.

Paturiet prātā, ka es biznesa loģikā faktiski neesmu ievietojis nevienu lietotāja saskarnes kodu. Esmu uzrakstījis lietotāja saskarnes slāni kā AWT (Abstract Window Toolkit) vai Swing, kas abi ir abstrakcijas slāņi. Faktiskais lietotāja saskarnes kods ir AWT / Swing ieviešanā. Tas ir abstrakcijas slāņa jēga - lai izolētu biznesa loģiku no apakšsistēmas mehānikas. Es viegli varu pārvietoties uz citu grafisko vidi, nemainot kodu, tāpēc vienīgā problēma ir neliela juceklis. Jūs varat viegli novērst šo jucekli, pārvietojot visu lietotāja saskarnes kodu iekšējā klasē (vai izmantojot fasādes dizaina modeli).

Java pupiņas

Jūs varētu iebilst, sakot: "Bet kā ir ar JavaBeans?" Kas ir ar viņiem? Jūs noteikti varat izveidot JavaBeans bez getters un seteriem. The BeanCustomizer, BeanInfo, un BeanDescriptor klases visas pastāv tieši šim nolūkam. JavaBean spec dizaineri attēlā iemeta getter / setter idiomu, jo uzskatīja, ka tas būs vienkāršs veids, kā ātri pagatavot pupiņu - kaut ko jūs varat darīt, kamēr jūs mācāties, kā to izdarīt pareizi. Diemžēl neviens to nedarīja.

Piekļuves ierīces tika izveidotas tikai kā veids, kā iezīmēt noteiktus rekvizītus, lai lietotāja interfeisa veidotāja vai līdzvērtīga programma varētu tos identificēt. Jums nevajadzētu pats saukt šīs metodes. Tie pastāv automatizēta rīka izmantošanai. Šis rīks izmanto iekšējās apskates API Klase klasei, lai atrastu metodes un ekstrapolētu noteiktu īpašību esamību no metožu nosaukumiem. Praksē šī introspekcijā balstītā idioma nav izdevusies. Tas ir padarījis kodu pārāk sarežģītu un procesuālu. Programmētāji, kuri nesaprot datu ieguvi, faktiski zvana pie piekļuvējiem, un tāpēc kods ir mazāk uzturams. Šī iemesla dēļ metadatu funkcija tiks integrēta Java 1.5 (paredzēts 2004. gada vidū). Tātad, nevis:

privāts int īpašums; public int getProperty () {return property; } public void setProperty (int vērtība} {īpašums = vērtība;} 

Jūs varēsiet izmantot kaut ko līdzīgu:

privāts @ īpašums int īpašums; 

Lietotāja saskarnes konstruēšanas rīks vai ekvivalents izmantos introspekcijas API, lai atrastu īpašības, nevis pārbauda metožu nosaukumus un secina īpašuma esamību no nosaukuma. Tādēļ neviens izpildlaika piekļuvējs nesabojā jūsu kodu.

Kad piekļuvējs ir kārtībā?

Pirmkārt, kā es jau iepriekš apspriedu, ir pareizi, ja metode atgriež objektu interfeisa izteiksmē, ko objekts īsteno, jo šī saskarne jūs izolē no izmaiņām ieviešanas klasē. Šāda veida metode (kas atgriež saskarnes atsauci) patiesībā nav "getter" tādas metodes nozīmē, kas tikai nodrošina piekļuvi laukam. Ja maināt pakalpojumu sniedzēja iekšējo ieviešanu, vienkārši mainiet atgrieztā objekta definīciju, lai pielāgotos izmaiņām. Jūs joprojām aizsargājat ārējo kodu, kas izmanto objektu, izmantojot tā saskarni.

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