Programmēšana

Iekapsulēšana nav informācijas slēpšana

Vārdi ir slideni. Tāpat kā Luits Kerols pasludināja Humpty Dumpty Caur skatlogu, "Kad es lietoju vārdu, tas nozīmē tikai to, ko es izvēlos, lai tas nozīmētu - ne vairāk, ne mazāk." Noteikti vārdu kopīgais lietojums iekapsulēšana un informācijas slēpšana šķiet, ka ievēro šo loģiku. Autori reti izšķir abus un bieži tieši apgalvo, ka tie ir vienādi.

Vai tas to padara? Nav domāts man. Ja tas būtu vienkārši vārdu jautājums, es nerakstītu nevienu vārdu par šo jautājumu. Bet aiz šiem terminiem ir divi atšķirīgi jēdzieni, atsevišķi radīti un vislabāk saprotami jēdzieni.

Iekapsulēšana attiecas uz datu apvienošanu ar metodēm, kas darbojas ar šiem datiem. Bieži vien šo definīciju nepareizi saprot, ka dati kaut kādā veidā tiek paslēpti. Java var būt iekapsulēti dati, kas vispār nav paslēpti.

Tomēr datu slēpšana nav visa informācijas slēpšanas pakāpe. Deivids Parnass pirmo reizi ieviesa informācijas slēpšanas jēdzienu ap 1972. gadu. Viņš apgalvoja, ka primārajiem sistēmas modulēšanas kritērijiem vajadzētu būt kritisku dizaina lēmumu slēpšanai. Viņš uzsvēra, ka slēpjas "sarežģīti dizaina lēmumi vai dizaina lēmumi, kas, iespējams, mainīsies". Šāda informācijas slēpšana izolē klientus no nepieciešamības pēc intīmām zināšanām par dizainu, lai izmantotu moduli, un no šo lēmumu maiņas sekām.

Šajā rakstā es izpētīju atšķirību starp iekapsulēšanu un informācijas slēpšanu, izstrādājot koda paraugu. Diskusija parāda, kā Java atvieglo iekapsulēšanu un pēta iekapsulēšanas negatīvās sekas, neslēpjot datus. Piemēri arī parāda, kā uzlabot klases dizainu, izmantojot informācijas slēpšanas principu.

Pozīcijas klase

Pieaugot izpratnei par bezvadu interneta milzīgo potenciālu, daudzi speciālisti sagaida, ka uz atrašanās vietu balstītie pakalpojumi sniegs iespēju pirmajai bezvadu slepkavas lietotnei. Šī raksta parauga kodam esmu izvēlējies klasi, kas atspoguļo punkta ģeogrāfisko atrašanās vietu uz zemes virsmas. Kā domēna entītija, klase ar nosaukumu Pozīcija, atspoguļo globālās pozicionēšanas sistēmas (GPS) informāciju. Pirmais griezums klasē izskatās tik vienkārši:

publiskā klase Pozīcija {public double latitude; valsts dubultā garums; } 

Klasē ir divi datu elementi: GPS platums un garums. Tagadnē, Pozīcija ir nekas cits kā mazs datu maiss. Tomēr Pozīcija ir klase, un Pozīcija objektus var precizēt, izmantojot klasi. Lai izmantotu šos objektus, klase PositionUtility satur metodes attāluma un virziena - tas ir, virziena - aprēķināšanai starp norādītajiem Pozīcija objekti:

public class PositionUtility {public static double distance (Position position1, Position position2) {// Aprēķiniet un atgrieziet attālumu starp norādītajām pozīcijām. } public static double title (Pozīcijas pozīcija1, Pozīcijas pozīcija2) {// Aprēķiniet un atgrieziet virsrakstu no pozīcijas1 uz pozīciju2. }} 

Es attālumu un virziena aprēķināšanai izlaižu faktisko ieviešanas kodu.

Šis kods apzīmē tipisku Pozīcija un PositionUtility:

// Izveidot pozīciju, kas attēlo manu māju Pozīcija myHouse = new Position (); myHouse.latitude = 36.538611; myHouse.longitude = -121,797500; // Izveidot pozīciju, kas pārstāv vietējo kafijas veikalu Position coffeeShop = new Position (); coffeeShop.latitude = 36.539722; coffeeShop.longitude = -121.907222; // Izmantojiet PositionUtility, lai aprēķinātu attālumu un virzienu no manas mājas // uz vietējo kafejnīcu. dubultā distance = PositionUtility.distance (myHouse, coffeeShop); dubultraksts = PositionUtility.heading (mana māja, kafijas veikals); // Drukāt rezultātus System.out.println ("No manas mājas ((+ + mana māja.latitude +", "+ myHouse.longitude +")) līdz kafejnīcai ("+ coffeeShop.latitude +", "+ coffeeShop. garums + ") ir attālums" + attālums + "pozīcijā" + virsraksts + "grādi."); 

Kods ģenerē izeju zemāk, kas norāda, ka kafejnīca atrodas tieši uz rietumiem (270,8 grādi) no manas mājas 6,09 attālumā. Vēlākā diskusija pievēršas attāluma vienību trūkumam.

 ==================================================== ================= No manas mājas (36.538611, -121.7975) līdz kafejnīcai (36.539722, -121.907222) ir 6.0873776351893385 attālums 270.7547022304523 grādu virzienā. ==================================================== ================= 

Pozīcija, PositionUtility, un to koda lietošana ir mazliet satraucoša un noteikti nav īpaši orientēta uz objektu. Bet kā tas var būt? Java ir uz objektu orientēta valoda, un kods izmanto objektus!

Lai arī kods var izmantot Java objektus, tas tiek darīts tādā veidā, kas atgādina aizgājušo laikmetu: utilītu funkcijas, kas darbojas uz datu struktūrām. Laipni lūdzam 1972. gadā! Kad prezidents Niksons sarāvās pie slepeniem lentes ierakstiem, datoru speciālisti, kas kodēja procesuālajā valodā, Fortran satraukti izmantoja jauno Starptautisko matemātikas un statistikas bibliotēku (IMSL) tieši šādā veidā. Kodu krātuvēs, piemēram, IMSL, bija pilnas funkcijas ar skaitliskiem aprēķiniem. Lietotāji šīm funkcijām nodeva datus garos parametru sarakstos, kas reizēm ietvēra ne tikai ievades, bet arī izvades datu struktūras. (IMSL gadu gaitā turpināja attīstīties, un versija tagad ir pieejama Java izstrādātājiem.)

Pašreizējā dizainā Pozīcija ir vienkārša datu struktūra un PositionUtility ir IMSL stila bibliotēkas funkciju krātuve, kas darbojas Pozīcija dati. Kā redzams iepriekš minētajā piemērā, mūsdienu uz objektu orientētās valodas ne vienmēr izslēdz novecojušu, procesuālu paņēmienu izmantošanu.

Datu un metožu apvienošana

Kodu var viegli uzlabot. Iesācējiem, kāpēc datus un funkcijas, kas darbojas ar šiem datiem, ievietot atsevišķos moduļos? Java klases ļauj apvienot datus un metodes:

public class Position {public double distance (Position position) {// Aprēķiniet un atgrieziet attālumu no šī objekta norādītajā // pozīcijā. } public double title (Position position) {// Aprēķiniet un atgrieziet virsrakstu no šī objekta norādītajā // pozīcijā. } publiskā dubultā platuma grāda; valsts dubultā garums; } 

Pozīcijas datu vienumu un ieviešanas koda ievietošana attāluma un virziena aprēķināšanai vienā klasē novērš nepieciešamību pēc atsevišķas PositionUtility klasē. Tagad Pozīcija sāk atgādināt īstu objektorientētu klasi. Šis kods izmanto šo jauno versiju, kas apvieno datus un metodes:

Pozīcija myHouse = jauna pozīcija (); myHouse.latitude = 36.538611; myHouse.longitude = -121,797500; Pozīcija coffeeShop = new Position (); coffeeShop.latitude = 36.539722; coffeeShop.longitude = -121.907222; dubultā distance = myHouse.distance (kafijas veikals); dubultraksts = myHouse.heading (kafijas veikals); System.out.println ("No manas mājas vietnē (" + myHouse.latitude + "," + myHouse.longitude + ") līdz kafejnīcai (" + coffeeShop.latitude + "," + coffeeShop.longitude + ") ir attālums "+ attālums +" pozīcijā "+ virziens +" grādi. "); 

Izeja ir identiska kā iepriekš, un, vēl svarīgāk, iepriekš minētais kods šķiet dabiskāks. Iepriekšējā versija izturēja divas Pozīcija iebilst pret funkciju atsevišķā lietderības klasē, lai aprēķinātu attālumu un virzienu. Šajā kodā, aprēķinot virsrakstu ar metodes izsaukumu util.heading (mana māja, kafijas veikals) skaidri nenorādīja aprēķina virzienu. Izstrādātājam jāatceras, ka utilītas funkcija aprēķina virsrakstu no pirmā parametra uz otro.

Salīdzinājumam iepriekš minētais kods izmanto paziņojumu myHouse.heading (kafijas veikals) lai aprēķinātu to pašu virsrakstu. Zvana semantika skaidri norāda, ka virziens virzās no manas mājas uz kafejnīcu. Divu argumentu funkcijas konvertēšana virsraksts (pozīcija, pozīcija) uz viena argumenta funkciju position.heading (Pozīcija) ir pazīstams kā karija funkciju. Karijs efektīvi specializē funkciju tā pirmajā argumentā, kā rezultātā iegūst skaidrāku semantiku.

Metodu izvietošana, izmantojot Pozīcija klases dati Pozīcija klase pati par sevi padara funkciju kariju attālums un virsrakstu iespējams. Šādi mainīt funkciju izsaukuma struktūru ir būtiska priekšrocība salīdzinājumā ar procesuālajām valodām. Klase Pozīcija tagad apzīmē abstraktu datu tipu, kas ietver datus un algoritmus, kas darbojas ar šiem datiem. Kā lietotāja definēts tips, Pozīcija objekti ir arī pirmās klases pilsoņi, kuri izbauda visas Java valodas tipa sistēmas priekšrocības.

Valodas iespēja, kas apvieno datus ar darbībām, kuras veic ar šiem datiem, ir iekapsulēšana. Ņemiet vērā, ka iekapsulēšana negarantē ne datu aizsardzību, ne informācijas slēpšanu. Iekapsulēšana arī nenodrošina vienotu klases dizainu. Lai sasniegtu šos kvalitātes dizaina atribūtus, ir nepieciešamas metodes, kas pārsniedz valodas sniegto iekapsulēšanu. Kā šobrīd tiek īstenots, klase Pozīcija nesatur liekus vai nesaistītus datus un metodes, bet Pozīcija tomēr pakļauj abus platums un garums neapstrādātā veidā. Tas ļauj jebkuram klases klientam Pozīcija lai tieši mainītu jebkuru iekšējo datu vienību bez jebkādas Iejaukšanās Pozīcija. Skaidrs, ka ar iekapsulēšanu nepietiek.

Aizsardzības programmēšana

Lai turpinātu izpētīt iekšējo datu vienību pakļaušanas sekas, pieņemsim, ka es nolemju pievienot nedaudz aizsardzības programmu Pozīcija ierobežojot platumu un garumu līdz GPS norādītajiem diapazoniem. Platums nokrīt diapazonā [-90, 90] un garums diapazonā (-180, 180]. Datu vienību ekspozīcija platums un garums iekšā PozīcijaPašreizējā ieviešana padara šo aizsardzības programmēšanu neiespējamu.

Veicot atribūtu platumu un garumu Privāts klases locekļi Pozīcija un vienkāršu piekļuves un mutatora metožu pievienošana, ko parasti dēvē arī par getters un seteriem, nodrošina vienkāršu līdzekli neapstrādātu datu vienību atklāšanai. Tālāk esošajā koda piemērā setera metodes atbilstoši pārbauda parametra iekšējās vērtības platums un garums. Tā vietā, lai izmestu izņēmumu, es norādīju ievades vērtību moduļa aritmētiku, lai iekšējās vērtības noturētu noteiktos diapazonos. Piemēram, mēģinot iestatīt platumu uz 181,0, iekšējais iestatījums ir -179,0 platums.

Šis kods pievieno labākās un iestatītākās metodes piekļuvei privāto datu dalībniekiem platums un garums:

publiskā klase Pozīcija {publiskā pozīcija (dubultā platums, dubultā garums) {setLatitude (platums); setLongitude (garums); } public void setLatitude (double latitude) {// Nodrošiniet -90 <= platums <= 90, izmantojot moduļa aritmētiku. // Kods nav parādīts. // Pēc tam iestatiet instances mainīgo. this.latitude = platums; } public void setLongitude (double longitude) {// Nodrošiniet -180 <garums <= 180, izmantojot moduļa aritmētiku. // Kods nav parādīts. // Pēc tam iestatiet instances mainīgo. tas.garums = garums; } public double getLatitude () {return latitude; } public double getLongitude () {atgriešanās garums; } public double distance (Position position) {// Aprēķiniet un atgrieziet attālumu no šī objekta līdz norādītajai // pozīcijai. // Kods nav parādīts. } public double title (Position position) {// Aprēķiniet un atgrieziet virsrakstu no šī objekta norādītajā // pozīcijā. } privātā dubultā platuma grāda; privātā dubultā garums; } 

Izmantojot iepriekš minēto Pozīcija prasa tikai nelielas izmaiņas. Kā pirmās izmaiņas, jo iepriekš minētais kods norāda konstruktoru, kas aizņem divus dubultā argumenti, noklusējuma konstruktors vairs nav pieejams. Šajā piemērā tiek izmantots jaunais konstruktors, kā arī jaunās getter metodes. Rezultāts paliek tāds pats kā pirmajā piemērā.

Pozīcija myHouse = jauna pozīcija (36.538611, -121.797500); Pozīcija coffeeShop = new Position (36.539722, -121.907222); dubultā distance = myHouse.distance (kafijas veikals); dubultraksts = myHouse.heading (kafijas veikals); System.out.println ("No manas mājas ((+ + myHouse.getLatitude () +", "+ myHouse.getLongitude () +")) līdz kafejnīcai ("+ coffeeShop.getLatitude () +", "+ coffeeShop.getLongitude () + ") ir attālums" + attālums + "virsrakstā" + virsraksts + "grādi".); 

Izvēloties ierobežot pieņemamās vērtības platums un garums izmantojot setera metodes, ir stingri jāizlemj par dizainu. Iekapsulēšanai nav nozīmes. Tas ir, iekapsulēšana, kas izpaužas Java valodā, negarantē iekšējo datu aizsardzību. Kā izstrādātājs, jūs varat brīvi atmaskot savas klases iekšējos elementus. Neskatoties uz to, jums vajadzētu ierobežot piekļuvi iekšējiem datu vienumiem un to modificēšanu, izmantojot getter un setter metodes.

Potenciālo izmaiņu izolēšana

Iekšējo datu aizsardzība ir tikai viena no daudzajām problēmām, kas virza dizaina lēmumus papildus valodas iekapsulēšanai. Izolācija pārmaiņām ir vēl viena. Klases iekšējās struktūras pārveidošanai nevajadzētu, ja tas vien iespējams, ietekmēt klientu klases.

Piemēram, es iepriekš atzīmēju, ka distances aprēķins klasē Pozīcija nenorādīja vienības. Lai būtu lietderīgi, ziņotajam attālumam 6,09 no manas mājas līdz kafejnīcai nepārprotami nepieciešama mērvienība. Es, iespējams, zinu virzienu, kurā iet, bet nezinu, vai iet 6,09 metrus, braukt 6,09 jūdzes vai lidot 6,09 tūkstošus kilometru.

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