Përdoret programimi i orientuar nga objekti. Programim i orientuar nga objekti për fillestarët

Programimi i orientuar nga objekti (OOP) është aktualisht teknologjia më e njohur e programimit. Programimi i orientuar nga objekti është një zhvillim i teknologjisë së programimit të strukturuar, por ka veçoritë e veta karakteristike.

Sistemet më të zakonshme të programimit vizual të orientuar nga objekti janë Microsoft Visual Basic dhe Borland Delphi.

Programimi i orientuar nga objektet, në thelbin e tij, ka të bëjë me krijimin e aplikacioneve nga objektet, ashtu si shtëpitë ndërtohen nga blloqe dhe pjesë të ndryshme. Disa objekte duhet të krijohen tërësisht vetë, ndërsa të tjerët mund të huazohen të gatshme nga biblioteka të ndryshme.

Një vend të rëndësishëm në teknologjinë e programimit të orientuar nga objekti zë ngjarje. Ngjarjet mund të jenë një klikim i mausit mbi një objekt, shtypja e një tasti të caktuar, hapja e një dokumenti, etj. Si reagim ndaj ngjarjeve, quhet një procedurë e caktuar, e cila mund të ndryshojë vetitë e objektit, të thërrasë metodat e tij, etj.

Sistemet e programimit të orientuara nga objekti zakonisht përdorin një ndërfaqe grafike për të vizualizuar procesin e programimit. Bëhet e mundur krijimi i objekteve, vendosja e vetive dhe sjelljes së tyre duke përdorur miun.

Një objekt, nga njëra anë, ka veti të caktuara që karakterizojnë gjendjen e tij në një moment të caktuar kohor dhe, nga ana tjetër, janë të mundshme operacione që çojnë në ndryshime në vetitë.

Njësia bazë në programimin e orientuar nga objekti është një objekt që përmbledh si të dhënat që e përshkruajnë atë (vetitë) ashtu edhe mjetet për përpunimin e këtyre të dhënave (metodat).

Enkapsulimi është bashkimi i vetive të një objekti dhe operacioneve (metodave) të mundshme mbi të.

Një parim tjetër që qëndron në themel të OOP është mundësia e krijimit të një klase të re objektesh me trashëgimi të vetive dhe metodave të një klase tashmë ekzistuese.

Trashëgimia është aftësia për të nxjerrë një klasë nga një tjetër duke ruajtur të gjitha vetitë dhe metodat e klasës së paraardhësve (progenitor, ndonjëherë i quajtur superklasë) dhe duke shtuar, nëse është e nevojshme, veti dhe metoda të reja.

Një grup klasash të lidhura me trashëgimi quhet hierarki. Trashëgimia synon të pasqyrojë një pronë të tillë të botës reale si hierarkia.

Një parim tjetër i OOP është parimi i polimorfizmit.

Polimorfizmi është fenomeni në të cilin një funksion (metodë) me të njëjtin emër i korrespondon kodit të ndryshëm të programit (kodit polimorfik) në varësi të objektit të klasës që përdoret kur thirret kjo metodë.

Polimorfizmi sigurohet duke ndryshuar zbatimin e metodës së klasës paraardhëse në klasën pasardhëse me ruajtjen e detyrueshme të nënshkrimit të metodës. Kjo siguron që ndërfaqja e klasës paraardhëse të mbetet e pandryshuar dhe ju lejon të lidhni emrin e metodës në kod me klasa të ndryshme - nga objekti i cilës klasë bëhet thirrja, nga ajo klasë merret metoda me emrin e dhënë. Ky mekanizëm quhet lidhje dinamike (ose e vonshme) - në krahasim me lidhjen statike (të hershme), e cila kryhet në kohën e përpilimit

Qasja e orientuar nga objekti ju lejon të kombinoni një model statik që përshkruan vetitë e një objekti dhe një model dinamik që përshkruan ndryshimet e tyre.

Me këtë qasje, qasja në ndryshimin e vetive të një objekti është e mundur vetëm përmes metodave që i përkasin këtij objekti. Metodat "rrethojnë" vetitë e një objekti; pronat thuhet se janë "të kapsuluara" në një objekt.

Kështu, në programimin e orientuar nga objekti, një vend qendror zënë objektet që kombinojnë në një tërësi (inkapsulojnë) vetitë e një objekti dhe operacionet (metodat) e mundshme mbi të.

Objektet që përmbledhin të njëjtën listë të vetive dhe operacioneve kombinohen në klasat.Çdo objekt individual është një shembull i klasës. Instancat e një klase mund të kenë vlera të ndryshme të vetive.

Për shembull, sistemi i skedarëve të një kompjuteri mund të përmbajë qindra ose mijëra skedarë. Të gjithë skedarët kanë të njëjtin grup vetish (emri, pozicioni në sistemin e skedarëve, etj.) dhe operacione (riemërtimi, zhvendosja ose kopjimi, etj.) dhe formojnë një klasë objektesh Skedarët.

Çdo skedar individual është një shembull i kësaj klase dhe ka vlera specifike të vetive (emri, vendndodhja, etj.).

Shpesh ndodh një situatë kur të njëjtat operacione mund të kryhen në objekte të klasave të ndryshme. Shumica e klasave të objekteve në mjedisin Windows (dosjet, dokumentet, simbolet, etj.) karakterizohen gjithashtu nga një sërë veprimesh të njëjta (riemërtimi, lëvizja, kopjimi, fshirja, etj.). Ky uniformitet është shumë miqësor për përdoruesit.

Megjithatë, është e qartë se mekanizmat për zbatimin e këtyre operacioneve nuk janë të njëjta për klasa të ndryshme. Për shembull, për të kopjuar një dosje, duhet të kryeni një sekuencë veprimesh për të ndryshuar sistemin e skedarëve, dhe për të kopjuar një simbol, të bëni ndryshime në dokument. Këto operacione do të kryhen nga programe të ndryshme që janë të disponueshme, përkatësisht, në sistemin operativ Windows dhe në redaktuesin e tekstit Word.

Në këtë mënyrë realizohet polimorfizëm, ato. aftësia për të kryer të njëjtat operacione në objekte që i përkasin klasave të ndryshme, duke ruajtur metoda individuale për zbatimin e tyre për secilën klasë.

Formohen objekte që kanë grupe të njëjta vetive dhe metodash klasa e objektit. Pra, në aplikacionin Word ekziston një klasë objekti dokument(Dokumentet), i cili ka këto veti: Emri(Emri), vendndodhjention(FileNaine), etj. Objektet e kësaj klase kanë gjithashtu një grup të caktuar metodash, për shembull: hapja e një dokumentipolic(Hapur) printim dokumentesh(Shtypje), ruajtjesdokument(Ruaj), etj.

Objektet në aplikacione formojnë një lloj hierarkie. Në krye të hierarkisë së objektit është aplikacion(Aplikacion). Kështu, hierarkia e objekteve të aplikacionit Word përfshin objektet e mëposhtme: aplikacion(Aplikacion), dokument(Dokumentet), fragment dokumenti(Përzgjedhja), simbol(Personazh) etj.

Hierarkia e objekteve të aplikacionit Excel përfshin objektet e mëposhtme: aplikacion(Aplikacion), libër(Fletore pune), fletë(Fletë pune) diapazoni i qelizave(varg), qelizatka(Qeliza), etj.

Një referencë e plotë për një objekt përbëhet nga një seri emrash objektesh të vendosur në mënyrë sekuenciale brenda njëri-tjetrit. Ndarësit për emrat e objekteve në këtë seri janë pika; seria fillon me objektin e aplikacionit të nivelit më të lartë dhe përfundon me emrin e objektit me interes për ne. Për shembull, një lidhje me dokumentin Пpo6a.doc në Word do të duket kështu:

Aplikacion. Dokumentet("Ppo6a.doc")

Në mënyrë që një objekt të kryejë ndonjë operacion, duhet të specifikohet një metodë. Shumë metoda kanë argumente që ju lejojnë të specifikoni parametrat për veprimet që do të kryhen. Për të caktuar vlera specifike për argumentet, përdoren dy pika dhe një shenjë e barabartë, dhe argumentet ndahen me presje.

Në Visual Basic, objektet karakterizohen jo vetëm nga vetitë dhe metodat, por edhe ngjarjet. Një ngjarje është një veprim i njohur nga një objekt. Një ngjarje mund të gjenerohet nga përdoruesi (për shembull, shtypja e një butoni të miut ose një tasti në tastierë) ose të jetë rezultat i funksionimit të objekteve të tjera të aplikacionit.

Për çdo ngjarje, ju mund të programoni një përgjigje, domethënë reagimin e objektit ndaj ngjarjes që ka ndodhur. Ky program quhet procedurën e ngjarjes. Emri i procedurës së ngjarjes zakonisht përbëhet nga emri i objektit dhe emri i ngjarjes. Për shembull, për një objekt butoni me emrin Komanda1 dhe ngjarjet Klikoni(“klikoni” që ndodh kur lëvizim kursorin e miut mbi imazhin e butonit dhe shtypim butonin e majtë të miut) procedura e ngjarjes do të marrë emrin Komanda1_ Klikoni.

Disa objekte mund të marrin pjesë në një procedurë ngjarjeje. Për shembull, në procedurën e përmendur më lart Komanda1_ Klikoni ekipi mund të jetë i pranishëm

Teksti1. Teksti= "Përshëndetje!"

si rezultat i ekzekutimit të cilit në “fushën e tekstit” objekti me emrin Teksti1 Do të shfaqet një rresht me fjalën "Përshëndetje!".

Programimi vizual, metodat e të cilit përdoren nga mjedisi i zhvillimit të Visual Basic, ju lejon të krijoni një ndërfaqe grafike për aplikacionet e zhvilluara bazuar në përdorimin e elementeve të kontrollit, të cilat përfshijnë butonat(Butoni i komandës), kutitë e kontrollit(Kutia e kontrollit) , fushat e tekstit(Kuti teksti) kuti kombinuese(ListBox) dhe të tjerë. Këto objekte, vetitë dhe metodat e tyre do të diskutohen në seksionin vijues. Tani për tani, le të vërejmë se elementët e kontrollit përdoren më shpesh për të marrë të dhëna nga përdoruesi dhe për të shfaqur rezultatet e aplikacionit. Kështu, kontrollet janë baza për ndërtimin e ndërfaqes së përdoruesit të aplikacionit.

Objektet kryesore të përdorura në programimin vizual janë forma(Formulari). Një formë është një dritare në të cilën vendosen elementët e kontrollit. Një formë është gjithashtu një objekt i karakterizuar nga një grup vetive dhe metodash. Ashtu si me çdo objekt tjetër, ju mund të shkruani një procedurë ngjarje për një formë, për shembull Forma_ Ngarkoni, e cila niset kur ndodh ngjarja Load dhe si rezultat i së cilës do të ekzekutohen udhëzimet e nevojshme për funksionimin e aplikacionit të nisur.

Programimi i orientuar nga objekti (OOP) formon bazën e Java. Në thelb, të gjitha programet Java janë të orientuara nga objekti në një farë mase. Gjuha Java është aq e lidhur ngushtë me OOP, saqë përpara se të filloni të shkruani edhe programet më të thjeshta në të, së pari duhet të njiheni me parimet bazë të OOP. Prandaj, le të fillojmë duke shqyrtuar çështjet teorike të OOP.

Dy teknika

Të gjitha programet kompjuterike përbëhen nga dy elementë: kodi dhe të dhënat. Për më tepër, një program konceptualisht mund të organizohet rreth kodit ose të dhënave të tij. Me fjalë të tjera, organizimi i disa programeve përcaktohet nga "çfarë ndodh", ndërsa të tjerat përcaktohen nga "ajo që ndikohet". Ekzistojnë dy mënyra për të krijuar programe. E para prej tyre quhet model i orientuar nga procesi dhe karakterizon një program si një sekuencë hapash linearë (d.m.th., kod). Modeli i orientuar nga procesi mund të shihet si kodi që vepron mbi të dhënat. Ky model është përdorur me mjaft sukses në gjuhët procedurale si C. Por, siç u përmend në kapitullin 1, kjo qasje ngre një sërë vështirësish për shkak të rritjes së madhësisë dhe kompleksitetit të programeve.

Për të kapërcyer rritjen e kompleksitetit të programit, zhvillimi i një qasjeje të quajtur programimi i orientuar nga objekti. Programimi i orientuar nga objekti ju lejon të organizoni një program rreth të dhënave të tij (d.m.th., objekteve) dhe një grup ndërfaqesh të mirëpërcaktuara me këto të dhëna. Mund të karakterizohet një program i orientuar nga objekti si të dhëna që kontrollojnë aksesin në kod. Siç do të diskutohet më vonë, funksionet e menaxhimit të të dhënave kontraktuese mund të ofrojnë disa përfitime organizative.

Abstraksioni

Një element i rëndësishëm i OOP është abstraksioni.Është natyra njerëzore të përfaqësojë fenomene dhe objekte komplekse duke iu drejtuar abstraksionit. Për shembull, njerëzit e imagjinojnë një makinë jo si një koleksion prej dhjetëra mijëra pjesësh individuale, por si një objekt krejtësisht specifik që ka sjelljen e tij të veçantë. Ky abstraksion ju lejon të shmangni nevojën të mendoni për kompleksitetin e pjesëve që përbëjnë një makinë kur, të themi, drejtoni makinën në dyqan. Ju mund të injoroni detajet e motorit, kutisë së shpejtësisë dhe sistemit të frenave. Në vend të kësaj, objekti mund të përdoret si një njësi e vetme.

Klasifikimet hierarkike janë një mjet efektiv për zbatimin e abstraksionit. Kjo bën të mundur thjeshtimin e semantikës së sistemeve komplekse, duke i zbërthyer ato në pjesë më të menaxhueshme. Nga jashtë, makina duket si një objekt i vetëm. Por sapo shikoni brenda, bëhet e qartë se ai përbëhet nga disa nënsisteme: drejtimi, frenat, sistemi audio, rripat e sigurimit, ngrohës, navigator, etj. Secili prej këtyre nënsistemeve, nga ana tjetër, është mbledhur nga njësi më të specializuara. Për shembull, një sistem audio përbëhet nga një radio, CD player dhe/ose kaseta audio. Thelbi i gjithë kësaj është se struktura e një makine (ose çdo sistemi tjetër kompleks) mund të përshkruhet duke përdorur abstraksione hierarkike.

Abstraksionet hierarkike të sistemeve komplekse mund të aplikohen edhe në programet kompjuterike. Nëpërmjet abstraksionit, të dhënat e një programi tradicional të orientuar nga procesi mund të shndërrohen në objektet përbërëse të tij dhe sekuenca e hapave të procesit mund të shndërrohet në një grup mesazhesh të transmetuara midis këtyre objekteve. Kështu, secili prej këtyre objekteve përshkruan sjelljen e tij specifike. Këto objekte mund të konsiderohen entitete konkrete që u përgjigjen mesazheve që i udhëzojnë të shpjegojë një veprim specifik. Ky, në fakt, është i gjithë thelbi i OOP.

Parimet OOP qëndrojnë në themel të gjuhës Java dhe perceptimit njerëzor të botës. Është e rëndësishme të kuptohet se si zbatohen këto parime në programe. Siç do të bëhet e qartë më vonë, OOP është një teknikë tjetër, por më efektive dhe e natyrshme për krijimin e programeve që mund t'u mbijetojnë ndryshimeve të pashmangshme që shoqërojnë ciklin jetësor të çdo projekti të madh softuerësh, duke përfshirë fillimin e dizajnit, zhvillimit dhe maturimit të përgjithshëm. Për shembull, nëse keni objekte të përcaktuara me kujdes dhe ndërfaqe të qarta dhe të besueshme për ato objekte, mund të hiqni ose zëvendësoni në mënyrë të sigurtë dhe lehtësisht pjesë të sistemit të vjetër.

Tre parime të OOP

Të gjitha gjuhët e programimit të orientuara nga objekti ofrojnë mekanizma për të lehtësuar zbatimin e modelit të orientuar nga objekti. Këta mekanizma janë kapsulimi, trashëgimia dhe polimorfizmi. Le t'i shikojmë këto parime OOP individualisht.

Kapsulimi

Quhet mekanizmi që lidh kodin dhe të dhënat që ai manipulon, duke mbrojtur të dyja nga ndërhyrjet dhe abuzimet e jashtme kapsulimi. Enkapsulimi mund të konsiderohet si një guaskë mbrojtëse që mbron kodin dhe të dhënat nga aksesi i rastësishëm nga kodi tjetër jashtë guaskës. Qasja në kod dhe të dhëna brenda shell kontrollohet rreptësisht nga një ndërfaqe e përcaktuar me kujdes. Për të bërë një analogji të botës reale, merrni parasysh një transmetim automatik në një makinë. Ai përmbledh shumë informacione rreth makinës, duke përfshirë sasinë e përshpejtimit, pjerrësinë e sipërfaqes në të cilën lëviz dhe pozicionin e levës së ndërrimit të marsheve. Përdoruesi (në këtë rast shoferi) mund të ndikojë në këtë kapsulim kompleks vetëm në një mënyrë: duke lëvizur levën e ndërrimit të marsheve. Kutia e shpejtësisë nuk duhet të ndikohet, për shembull, nga treguesi i kthesës ose fshirëset e xhamit. Kështu, leva e ndërrimit të marsheve është një ndërfaqe e përcaktuar rreptësisht dhe në thelb e vetmja ndërfaqe me kutinë e marsheve. Për më tepër, ajo që ndodh brenda kutisë së shpejtësisë nuk ndikon në objektet jashtë saj. Për shembull, ndërrimi i marsheve nuk i ndez fenerët! Funksioni i ndërrimit automatik të marsheve është i kapsuluar, kështu që dhjetëra prodhues makinash mund ta zbatojnë atë si të duan. Por nga këndvështrimi i shoferit, të gjitha këto kuti ingranazhesh funksionojnë njësoj. Një parim i ngjashëm mund të zbatohet në programim. Fuqia e kodit të kapsuluar është se të gjithë e dinë se si ta përdorin atë, dhe për këtë arsye mund të përdoret pavarësisht nga detajet e zbatimit dhe pa frikë nga efektet anësore të papritura.

Thelbi i kapsulimit të ejava është klasa. Klasat do të diskutohen më në detaje në kapitujt vijues, por deri atëherë është e dobishme të jepet të paktën një përshkrim i shkurtër i tyre. Klasa përcakton strukturën dhe sjelljen (të dhënat dhe kodin) që do të ndahen nga një grup objektesh. Çdo objekt i një klase të caktuar përmban strukturë dhe sjellje që përcaktohen nga klasa, sikur objekti të ishte "i hedhur" në kallëpin e klasës. Prandaj, ndonjëherë objektet quhen raste të klasës. Kështu, një klasë është një konstrukt logjik, dhe një objekt është mishërimi fizik i tij.

Kur krijoni një klasë, ju përcaktoni kodin dhe të dhënat që përbëjnë klasën. Këto elemente quhen së bashku anëtarët klasës. Në veçanti, thirren të dhënat e përcaktuara në një klasë ndryshojnë anëtarët e tyre, ose variablat e shembullit, dhe kodi që vepron mbi të dhënat është metodat e anëtarëve ose thjesht metodat.(Ajo që e quajnë programuesit Java metodat, Programuesit C/C++ thërrasin funksione) Në programet e shkruara siç duhet në Java, metodat përcaktojnë se si përdoren variablat anëtare. Kjo do të thotë që sjellja dhe ndërfaqja e një klase përcaktohen nga metodat që veprojnë në të dhënat e shembullit të saj.

Për shkak se qëllimi i një klase është të përmbledhë strukturën komplekse të programit, ekzistojnë mekanizma për të fshehur strukturën komplekse të zbatimit brenda vetë klasës. Çdo metodë ose variabël në një klasë mund të shënohet si private ose publike. Hapur Ndërfaqja e një klase përfaqëson gjithçka që përdoruesit e jashtëm të klasës duhet ose mund të dinë. Mbyllur metodat dhe të dhënat mund të aksesohen vetëm me kod që është anëtar i një klase të caktuar. Prandaj, çdo kod tjetër që nuk është anëtar i kësaj klase nuk mund të aksesojë metodën ose variablin privat. Anëtarët privatë të një klase janë të aksesueshëm në pjesët e tjera të programit vetëm përmes metodave publike të klasës, dhe në këtë mënyrë eliminojnë mundësinë e kryerjes së veprimeve të paligjshme. Kjo, natyrisht, do të thotë që ndërfaqja publike duhet të dizajnohet me kujdes dhe nuk duhet të zbulojë detaje të panevojshme rreth funksionimit të brendshëm të klasës (Figura 1).

Oriz. 1.

Trashëgimia

Procesi me të cilin një objekt fiton vetitë e një tjetri quhet trashëgimisë. Ky është një parim shumë i rëndësishëm i OOP sepse trashëgimia ofron parimin e klasifikimit hierarkik. Siç u përmend më herët, shumica e njohurive bëhen të arritshme për asimilimin përmes klasifikimit hierarkik (d.m.th., nga lart-poshtë). Për shembull, Golden Retriever është pjesë e klasifikimit qentë, e cila, nga ana tjetër, i përket klasës gjitarët, dhe ai - në një klasë edhe më të madhe kafshëve. Pa hierarki, çdo objekt do të duhet të përcaktojë në mënyrë eksplicite të gjitha karakteristikat e tij. Por falë trashëgimisë, një objekt duhet të përcaktojë vetëm ato gjëra që e bëjnë atë të veçantë në klasë. Një objekt mund të trashëgojë atribute të përbashkëta nga objekti i tij prind. Kështu, mekanizmi i trashëgimisë ju lejon të bëni një objekt një rast të veçantë të një rasti më të përgjithshëm. Le ta shqyrtojmë këtë mekanizëm në më shumë detaje.

Si rregull, shumica e njerëzve e perceptojnë botën përreth tyre në formën e objekteve të ndërlidhura në mënyrë hierarkike, si kafshët, gjitarët dhe qentë. Nëse dëshironi të bëni një përshkrim abstrakt të kafshëve, mund të thoni se ato kanë veti të caktuara: madhësinë, nivelin e inteligjencës dhe sistemin skeletor. Kafshët gjithashtu kanë karakteristika të caktuara të sjelljes: hanë, marrin frymë dhe flenë. Ky përshkrim i vetive dhe sjelljes përbën një përkufizim klasës kafshëve.

Nëse do të përshkruanim një klasë më specifike të kafshëve, siç janë gjitarët, do të na duhej të specifikonim veti më specifike, siç janë lloji i dhëmbëve dhe gjëndrave të qumështit. Ky përkufizim quhet nënklasa kafshëve që i përkasin superklasa(klasa e prindërve) gjitarë. Dhe meqenëse gjitarët janë vetëm kafshë të përcaktuara më saktë, ata trashëgojnë të gjitha vetitë e kafshëve. Nënklasa e nivelit të ulët hierarkia e klasës trashëgon të gjitha vetitë e secilës prej klasave të saj mëmë (Fig. 2).

Oriz. 2.

Trashëgimia lidhet edhe me kapsulimin. Nëse një klasë e vetme përmbledh veti të caktuara, atëherë çdo nënklasë e saj do të ketë të njëjtat veti plusçdo shtesë që përcakton specializimin e saj (Fig. 3). Për shkak të këtij parimi kyç, kompleksiteti i programeve të orientuara nga objekti rritet në progresion aritmetik dhe jo gjeometrik. Nënklasa e re trashëgon atributet e të gjitha klasave të saj mëmë dhe për këtë arsye nuk ka ndërveprime të paparashikueshme me pjesën tjetër të kodit të sistemit.

Oriz. 3. Labradoriti trashëgon plotësisht vetitë e kapsuluara të të gjitha klasave të kafshëve mëmë

Polimorfizmi

Polimorfizmi(nga greqishtja "shumë forma") është një parim OOP që lejon të njëjtën ndërfaqe të përdoret për një klasë të përbashkët veprimesh. Çdo veprim varet nga situata specifike. Konsideroni, si shembull, një pirg që vepron si një listë e kundërt e dyqaneve. Le të themi se një program kërkon tre lloje stekash: për vlera të plota, për vlera numerike me pikë lundruese dhe për karaktere. Algoritmi i zbatimit për secilën nga këto rafte mbetet i njëjtë, pavarësisht dallimeve në të dhënat që ruhen në to. Në një gjuhë jo të orientuar nga objekti, manipulimi i pirgut do të kërkonte krijimin e tre grupeve të ndryshme të shërbimeve nën emra të veçantë. Në java, në sajë të parimit të polimorfizmit, mund të përcaktohet një grup i përbashkët shërbimesh për trajtimin e pirgut nën të njëjtët emra të zakonshëm.

Në përgjithësi, parimi i polimorfizmit shpesh shprehet me frazën "një ndërfaqe, metoda të shumta". Kjo do të thotë se është e mundur të zhvillohet një ndërfaqe e përbashkët për një grup aktivitetesh që lidhen së bashku. Kjo qasje zvogëlon kompleksitetin e programit, pasi e njëjta ndërfaqe përdoret për të specifikuar klasa e përgjithshme e veprimeve. Dhe zgjedhja veprim specifik(d.m.th. metoda) bëhet në lidhje me çdo situatë dhe është përgjegjësi e përpiluesit. Kjo e kursen programuesin që t'i bëjë këto zgjedhje me dorë. Ai vetëm duhet të kujtojë ndërfaqen e përgjithshme dhe ta zbatojë atë saktë.

Nëse vazhdojmë analogjinë me qentë, mund të themi se nuhatja e qenit është një veti polimorfike. Nëse një qen nuhat një mace, ajo do të leh dhe do ta ndjekë atë. Dhe nëse qeni nuhat ushqimin e tij, ai do të fillojë të pështyjë dhe do të nxitojë në tasin e tij. Në të dyja rastet funksionon e njëjta shqisa e nuhatjes. Dallimi i vetëm është se çfarë lëshon saktësisht erën, d.m.th. në llojin e të dhënave që prek hundën e qenit! Ky parim i përgjithshëm mund të zbatohet duke e zbatuar atë në metodat në një program Java.

Përdorimi i kombinuar i polimorfizmit, kapsulimit dhe trashëgimisë

Kur parimet e polimorfizmit, kapsulimit dhe trashëgimisë zbatohen në mënyrë korrekte, ato së bashku formojnë një mjedis programimi që mbështet zhvillimin e programeve që janë më të fuqishme dhe të shkallëzueshme sesa do të ishte rasti me një model të orientuar drejt procesit. Një hierarki klasash e dizajnuar me kujdes ofron një bazë të fortë për ripërdorimin e kodit që keni shpenzuar kohë dhe përpjekje për të zhvilluar dhe testuar. Enkapsulimi ju lejon të ktheheni te zbatimet e krijuara më parë pa thyer kodin që varet nga ndërfaqja publike e klasave të përdorura në aplikacion. Dhe polimorfizmi ju lejon të krijoni kod të qartë, praktik, të lexueshëm dhe të qëndrueshëm.

Nga dy shembujt e jetës reale të dhëna më parë, shembulli i makinave ilustron më plotësisht aftësitë e OOP. Ndërsa shembulli i qenve është mjaft i përshtatshëm për të marrë në konsideratë OOP nga pikëpamja e trashëgimisë, shembulli i makinave ka më shumë të përbashkëta me programet. Kur drejtoni lloje të ndryshme (nënklasa) makinash, të gjithë drejtuesit përdorin trashëgimi. Nëse automjeti është një autobus shkolle, një makinë pasagjerësh, një makinë sportive ose një furgon familjar, të gjithë drejtuesit do të jenë në gjendje të gjejnë dhe të përdorin lehtësisht timonin, frenat dhe pedalin e gazit. Me pak ngacmim me levën e marsheve, shumica e njerëzve madje mund të vlerësojnë ndryshimet midis një transmetimi manual dhe një automatik, për sa kohë që ata kanë një kuptim të qartë të klasës së përbashkët prindërore të të dyve, sistemit të transmisionit.

Kur përdorin makina, njerëzit vazhdimisht ndërveprojnë me karakteristikat e tyre të kapsuluara. Pedalet e frenave dhe gazit fshehin kompleksitetin e jashtëzakonshëm të objekteve përkatëse pas një ndërfaqeje aq të thjeshtë sa që për të kontrolluar këto objekte ju duhet vetëm të shtypni pedalin me këmbën tuaj! Implementimi specifik i motorit, lloji i frenave dhe madhësia e gomave nuk kanë ndikim në mënyrën se si ato ndërveprojnë me përcaktimin e klasës së pedalit.

Së fundi, polimorfizmi pasqyron qartë aftësinë e prodhuesve të automobilave për të ofruar një shumëllojshmëri të gjerë opsionesh për në thelb të njëjtin automjet. Për shembull, automjeti mund të pajiset me frena kundër bllokimit ose frena tradicionale, timon me energji elektrike ose timon me raft dhe shtyllë, dhe motorë me 4, 6 ose 8 cilindra. Por në çdo rast, do t'ju duhet të shtypni pedalin e frenave për të ndaluar, të rrotulloni timonin për t'u kthyer dhe të shtypni pedalin e gazit për ta bërë makinën të lëvizë më shpejt. E njëjta ndërfaqe mund të përdoret për të kontrolluar një shumëllojshmëri të gjerë zbatimesh.

Siç mund ta shihni, falë aplikimit të kombinuar të parimeve të kapsulimit, trashëgimisë dhe polimorfizmit, pjesët individuale mund të shndërrohen në një objekt të quajtur makinë. E njëjta gjë vlen edhe për programet kompjuterike. Parimet OOP bëjnë të mundur ndërtimin e një programi koherent, të besueshëm, të mirëmbajtur nga shumë pjesë të veçanta.

Siç u përmend në fillim të këtij seksioni, çdo program Java është i orientuar drejt objektit. Më saktësisht, çdo program Hajava zbaton parimet e kapsulimit, trashëgimisë dhe polimorfizmit. Në pamje të parë, mund të duket se jo të gjitha këto parime shfaqen në shembujt e shkurtër të programeve të dhëna në pjesën tjetër të këtij kapitulli dhe në një numër kapitujsh pasues, por megjithatë ato janë të pranishme në to. Siç do të bëhet e qartë më vonë, shumë veçori të gjuhës Java janë pjesë e bibliotekave të integruara të klasës që përdorin gjerësisht parimet e kapsulimit, trashëgimisë dhe polimorfizmit.

Ndoshta gjysma e vendeve të lira (nëse jo më shumë) kërkojnë njohuri dhe kuptim të OOP. Po, kjo metodologji ka mahnitur padyshim shumë programues! Zakonisht, të kuptuarit e OOP vjen me përvojë, pasi praktikisht nuk ka materiale të përshtatshme dhe të arritshme për këtë temë. Dhe edhe nëse ka, nuk është aspak e sigurt që lexuesit do të pengohen me to. Shpresoj se do të jem në gjendje të shpjegoj parimet e kësaj metodologjie të mrekullueshme, siç thonë ata, në gishtat e mi.

Pra, tashmë në fillim të artikullit kam përmendur tashmë termin "metodologji". Kur aplikohet në programim, ky term nënkupton praninë e çdo grupi mënyrash për të organizuar kodin, metodat e shkrimit të tij, duke iu përmbajtur të cilave, programuesi do të jetë në gjendje të shkruajë programe plotësisht të përdorshme.

OOP (ose programimi i orientuar nga objekti) është një mënyrë e organizimit të kodit të programit ku blloqet kryesore të ndërtimit të programit janë objektet dhe klasat, dhe logjika e programit bazohet në ndërveprimin e tyre.


Rreth objekteve dhe klasave

Klasa- kjo është një strukturë e të dhënave që mund të krijohet nga vetë programuesi. Në terma OOP, një klasë përbëhet nga fusha(me fjalë të thjeshta - variabla) dhe metodat(me fjalë të thjeshta - funksionet). Dhe, siç doli, kombinimi i të dhënave dhe funksioneve për të punuar në të në një strukturë jep fuqi të paimagjinueshme. Nje objektështë një shembull specifik i një klase. Pas analogjisë së një klase me një strukturë të dhënash, një objekt është një strukturë specifike e të dhënave që ka disa vlera të caktuara në fushat e saj. Më lejoni të shpjegoj me një shembull:

Le të themi se duhet të shkruajmë një program që llogarit perimetrin dhe sipërfaqen e një trekëndëshi, i cili jepet nga dy brinjë dhe këndi midis tyre. Për të shkruar një program të tillë duke përdorur OOP, do të na duhet të krijojmë një klasë (domethënë një strukturë) Triangle. Klasa Triangle do të ruajë tre fusha (tre variabla): anën A, anën B, këndin ndërmjet tyre; dhe dy metoda (dy funksione): njehsoni perimetrin, njehsoni sipërfaqen. Me këtë klasë mund të përshkruajmë çdo trekëndësh dhe të llogarisim perimetrin dhe sipërfaqen. Pra, një trekëndësh specifik me brinjë specifike dhe një kënd midis tyre do të quhet shembull i klasës së Trekëndëshit. Kështu, një klasë është një shabllon, dhe një shembull është një zbatim konkret i shabllonit. Por instancat janë objekte, domethënë elementë specifikë që ruajnë vlera specifike.

Një nga gjuhët më të zakonshme të programimit të orientuar nga objekti është java. Atje thjesht nuk mund të bësh pa përdorur objekte. Kështu do të duket kodi për një klasë që përshkruan një trekëndësh në këtë gjuhë:

/** * Klasa e trekëndëshit. */ class Triangle ( /** * Metodë speciale e quajtur konstruktori i klasës. * Merr si hyrje tre parametra: * gjatësia e anës A, gjatësia e anës B, * këndi midis këtyre anëve (në gradë) */ Trekëndëshi (ana e dyfishtë A, e dyfishtë anaB , këndi i dyfishtëAB) (kjo.ana = anaA; kjo.anaB = anaB; kjo.këndiAB = këndAB; ) ana e dyfishtëA; //Fusha e klasës, ruan vlerën e anës A në trekëndëshin e përshkruar nga ana e dyfishtëB; //Fusha e klasës , ruan vlerën e anës B në trekëndëshin e përshkruar me kënd të dyfishtëAB; //Fusha e klasës ruan këndin (në gradë) midis dy anëve në trekëndëshin e përshkruar /** * Metoda e klasës që llogarit sipërfaqen e trekëndëshit */ double getSquare() ( double square = this.sideA * this .sideB * Math.sin(this.angleAB * Math.PI / 180); return katror; ) /** * Metoda e klasës që llogarit perimetrin e një trekëndëshi */ double getPerimeter() ( double sideC = Math.sqrt(Math.pow (this.sideA, 2) + Math.pow(this.sideB, 2) - 2 * this.sideA * this.sideB * Math.cos(this. këndAB * Math.PI / 180)); perimetri i dyfishtë = kjo.anaA + kjo.anaB + anaC; perimetri i kthimit; ))

Nëse shtojmë kodin e mëposhtëm brenda klasës:

/** * Këtu ekzekutohet programi */ public static void main (String args) ( //Vlerat 5, 17, 35 hyjnë në konstruktorin e klasës Triangle Triangle triangle1 = new Triangle(5, 17, 35 ); System.out .println ("Sipërfaqja e trekëndëshit1: "+triangle1.getSquare()); System.out.println("Perimetri i trekëndëshit1: "+triangle1.getPerimeter()); //Vlerat 6 , 8, 60 shkoni te konstruktori i klasës Triangle Triangle triangle2 = trekëndësh i ri (6, 8, 60); System.out.println ("Zona e trekëndëshit1: "+triangle2.getSquare()); System.out.println ("Perimetri i trekëndëshit1: "+triangle2.getPerimeter()); )

atëherë programi tashmë mund të niset për ekzekutim. Kjo është një veçori e gjuhës java. Nëse klasa ka një metodë të tillë

Kryesor publik statik i zbrazët (args varg)

atëherë kjo klasë mund të ekzekutohet. Le të shohim kodin në më shumë detaje. Le të fillojmë me linjën

Trekëndëshi trekëndësh1 = trekëndësh i ri(5, 17, 35);

Këtu krijojmë një shembull të trekëndëshit1 të klasës Triangle dhe i japim menjëherë parametrat e brinjëve dhe këndin ndërmjet tyre. Në të njëjtën kohë, thirret një metodë speciale e quajtur konstruktor dhe mbush fushat e objektit me vlerat që i kalojnë konstruktorit. Epo, po për linjat?

System.out.println("Sipërfaqja e trekëndëshit1: "+triangle1.getSquare()); System.out.println("Perimetri i trekëndëshit1: "+triangle1.getPerimeter());

nxirrni zonën e llogaritur të trekëndëshit dhe perimetrin e tij në tastierë.

E njëjta gjë ndodh edhe për shkallën e dytë të klasës Triangle.

Kuptimi i thelbit të klasave dhe ndërtimi i objekteve konkrete është një hap i parë i sigurt për të kuptuar metodologjinë OOP.

Edhe një herë, gjëja më e rëndësishme:

OOP- kjo është një mënyrë e organizimit të kodit të programit;

Klasa- kjo është një strukturë e personalizuar e të dhënave që bashkon të dhënat dhe funksionet për të punuar me to (fushat e klasës dhe metodat e klasës);

Nje objektështë një shembull specifik i një klase, fushave të së cilës u jepen vlera specifike.


Tre fjalë magjike

OOP përfshin tre qasje kryesore: trashëgiminë, kapsulimin dhe polimorfizmin. Për të filluar, unë do të jap përkufizime nga wikipedia:

Encapsulation është një veti e sistemit që ju lejon të kombinoni të dhënat dhe metodat që punojnë me to në një klasë. Disa gjuhë (p.sh. C++) e barazojnë kapsulimin me fshehjen, por shumica (Smalltalk, Eiffel, OCaml) bëjnë dallimin midis këtyre koncepteve.

Trashëgimia është një veçori e sistemit që ju lejon të përshkruani një klasë të re bazuar në një ekzistuese me funksione të huazuar pjesërisht ose plotësisht. Klasa nga e cila rrjedh trashëgimia quhet bazë, prind ose superklasa. Një klasë e re është një klasë pasardhëse, trashëgimtare, fëmijë ose e prejardhur.

Polimorfizmi është një veti e sistemit që ju lejon të përdorni objekte me të njëjtën ndërfaqe pa informacion në lidhje me llojin dhe strukturën e brendshme të objektit.

Të kuptuarit se çfarë nënkuptojnë në të vërtetë të gjitha këto përkufizime është mjaft e vështirë. Në librat e specializuar që mbulojnë këtë temë, çdo përkufizim shpesh i kushton një kapitull të tërë, por të paktën një paragraf. Megjithëse, thelbi i asaj që një programues duhet të kuptojë dhe të ngulitë përgjithmonë në trurin e tij është shumë i vogël.
Dhe si shembull për analizë, ne do të përdorim figurat në një aeroplan. Nga gjeometria e shkollës dimë se për të gjitha figurat e përshkruara në një plan, është e mundur të llogaritet perimetri dhe sipërfaqja. Për shembull, për një pikë të dy parametrat janë të barabartë me zero. Për një segment, ne mund të llogarisim vetëm perimetrin. Dhe për një katror, ​​drejtkëndësh ose trekëndësh - të dyja. Tani do ta përshkruajmë këtë detyrë në terma OOP. Është gjithashtu e dobishme për të kuptuar zinxhirin e arsyetimit që rezulton në hierarkinë e klasës, e cila, nga ana tjetër, mishërohet në kodin e punës. Shko:


Pra, një pikë është figura më e vogël gjeometrike, e cila është baza e të gjitha ndërtimeve të tjera (figurave). Prandaj, pika u zgjodh si klasa mëmë bazë. Le të shkruajmë një klasë pikë në Java:

/** * Klasa e pikëve. Klasa bazë */ class Point ( /** * Konstruktor bosh */ Point() () /** * Metoda e klasës që llogarit sipërfaqen e një figure */ double getSquare() (kthim 0;) /** * Metoda e klasës që llogarit perimetrin e figurës */ double getPerimeter() ( return 0; ) /** * Metoda e klasës që kthen një përshkrim të figurës */ String getDescription() ( return "Point"; ) )

Klasa Point që rezulton ka një konstruktor bosh, pasi në këtë shembull po punojmë pa koordinata specifike dhe operojmë vetëm me parametra dhe vlera anësore. Meqenëse pika nuk ka anë, nuk ka nevojë t'i kaloni asnjë parametër. Gjithashtu vini re se klasa ka metoda Point::getSquare() dhe Point::getPerimeter() për llogaritjen e sipërfaqes dhe perimetrit, të dyja kthejnë 0. Për një pikë, kjo është logjike.


Meqenëse pika jonë është baza e të gjitha figurave të tjera, ne trashëgojmë klasat e këtyre figurave të tjera nga klasa Point. Le të përshkruajmë klasën e një segmenti të trashëguar nga klasa e një pike:

/** * Segmenti i linjës së klasës */ klasa LineSegment zgjeron pikën (Segmenti i linjës(Gjatësia e segmentit të dyfishtë) ( this.segmentLength = Gjatësia e segmentit; ) Gjatësia e segmentit të dyfishtë; // Gjatësia e rreshtit /** * Metoda e klasës së anashkaluar që llogarit sipërfaqen e rreshti */ double getSquare( ) ( return 0; ) /** * Metoda e klasës së kapërcyer që llogarit perimetrin e një segmenti */ double getPerimeter() ( return this.segmentLength; ) String getDescription() ( return "Gjatesia e segmentit: " + this.segmentLength; ) )

Klasa LineSegment zgjeron pikën

do të thotë që klasa LineSegment trashëgon nga klasa Point. Metodat LineSegment::getSquare() dhe LineSegment::getPerimeter() anashkalojnë metodat përkatëse të klasës bazë. Sipërfaqja e një segmenti është gjithmonë zero, dhe sipërfaqja e perimetrit është e barabartë me gjatësinë e këtij segmenti.

Tani, si klasa e segmentit, ne përshkruajmë klasën e trekëndëshit (e cila gjithashtu trashëgon nga klasa e pikës):

/** * Klasa e trekëndëshit. */ Klasa Trekëndëshi zgjeron pikën ( /** * Konstruktori i klasës. Merr tre parametra si hyrje: * gjatësia e anës A, gjatësia e anës B, * këndi midis këtyre brinjëve (në gradë) */ Trekëndëshi (ana e dyfishtë A, ana e dyfishtë B, këndi i dyfishtëAB ) ( this.sideA = sideA; this.sideB = sideB; this.angleAB = angleAB; ) double sideA; //Fusha e klasës, ruan vlerën e anës A në trekëndëshin e përshkruar nga ana e dyfishtëB; //Fusha e klasës, ruan vlera e anës B në trekëndëshin e përshkruar të trekëndëshit me kënd të dyfishtëAB; //Fusha e klasës që ruan këndin (në gradë) midis dy anëve në trekëndëshin e përshkruar /** * Metoda e klasës që llogarit sipërfaqen e një trekëndëshi */ dyfish getSquare() ( katror i dyfishtë = (this.sideA * this.sideB * Math.sin(this.angleAB * Math.PI / 180))/2; ktheje katror;) /** * Metoda e klasës që llogarit perimetrin e një trekëndësh */ double getPerimeter() ( ana e dyfishtëC = Math.sqrt(Math. pow(this.sideA, 2) + Math.pow(this.sideB, 2) - 2 * this.sideA * this.sideB * Math.cos (this.angleAB * Math.PI / 180)); perimetri i dyfishtë = kjo.anaA + kjo.anaB + anaC; perimetri i kthimit; ) String getDescription() ( kthen "Trekëndësh me brinjë: " + this.sideA + ", " + this.sideB + " dhe kënd midis tyre: " + this.angleAB; ) )

Nuk ka asgjë të re këtu. Gjithashtu, metodat Triangle::getSquare() dhe Triangle::getPerimeter() anashkalojnë metodat përkatëse të klasës bazë.
Epo, tani, në fakt, vetë kodi që tregon magjinë e polimorfizmit dhe zbulon fuqinë e OOP:

Klasa kryesore ( /** * Këtu funksionon programi */ public static void main(String args) ( //ArrayList - Kjo është një strukturë e veçantë e të dhënave në java // që ju lejon të ruani objekte të një lloji të caktuar në një array.Figura ArrayList = ArrayList i ri (); 17, 55)); për (int i = 0;i

Ne kemi krijuar një grup objektesh të klasës Point, dhe meqenëse klasat LineSegment dhe Triangle trashëgojnë nga klasa Point, ne mund t'i vendosim ato në këtë grup. Rezulton se çdo figurë që është në grupin e figurave mund ta konsiderojmë si një objekt të klasës Point. Ky është polimorfizmi: nuk dihet se cilës klasë i përkasin objektet në grupin e figurave, por duke qenë se të gjitha objektet brenda këtij grupi i përkasin të njëjtës klasë bazë Point, atëherë të gjitha metodat që janë të zbatueshme për klasën Point janë gjithashtu të zbatueshme. tek klasat pasardhëse të saj.


Tani në lidhje me kapsulimin. Fakti që ne vendosëm parametrat e një figure dhe metodat për llogaritjen e sipërfaqes dhe perimetrit në një klasë është kapsulim; ne i përmbledhëm figurat në klasa të veçanta. Fakti që ne përdorim një metodë të veçantë në klasë për të llogaritur perimetrin është enkapsulimi; ne e kemi kapsuluar llogaritjen e perimetrit në metodën getPerimiter(). Me fjalë të tjera, kapsulimi po fsheh zbatimin (ndoshta përkufizimi më i shkurtër, dhe në të njëjtën kohë, më i gjerë i kapsulimit).


Kodi i plotë shembull:

Importo java.util.ArrayList; class Main ( /** * Këtu ekzekutohet programi */ public static void main(String args) ( //ArrayList është një strukturë e veçantë e të dhënave në java // që ju lejon të ruani objekte të një lloji të caktuar në një grup. Shifrat e ArrayList = ArrayList i ri (); //shtoni tre objekte të ndryshme te figurat array figures.add(new Point()); figures.add(new LineSegment(133)); figures.add(new Triangle(10, 17, 55)); për (int i = 0;i

në thelb përdori paradigmën e programimit përshkrues - qëllimi ishte krijimi i kodit që vepronte siç duhet në të dhënat. Kjo qasje është e mirë për zgjidhjen e problemeve të vogla, por krijon shumë probleme të pazgjidhshme kur përpiqeni të krijoni sisteme të mëdha softuerike.

Një nga alternativat programimi direktivështë programimi i orientuar nga objekti, e cila vërtetë ndihmon për të përballuar kompleksitetin jolinear në rritje të programeve ndërsa vëllimi i tyre rritet. Megjithatë, nuk duhet të arrihet në përfundimin se përdorimi i paradigmës së programimit të orientuar nga objekti garanton një zgjidhje të suksesshme për të gjitha problemet.

Për t'u bërë profesionist në programim, ju duhet talent, kreativitet, inteligjencë, njohuri, logjikë, aftësi për të ndërtuar dhe përdorur abstraksione dhe, më e rëndësishmja, përvojë.

Në këtë pjesë, ne do të vazhdojmë prezantimin tonë me konceptet bazë të programimit të orientuar drejt objekteve, të cilat e filluam në kapitullin e parë të librit. Së pari, do të diskutohen konceptet OOP të përbashkëta për gjuhë të ndryshme programimi, dhe më pas do të diskutohen zbatimi i tyre në gjuhën Java.

Duhet të jeni të vetëdijshëm se kursi mbi programimin e orientuar nga objekti u mësohet studentëve të diplomuar gjatë një semestri të tërë, dhe për këtë arsye materiali i paraqitur më poshtë përfaqëson vetëm një hyrje shumë themelore në botën e OOP. Një trajtim shumë më i plotë i shumë prej çështjeve që lidhen me dizajnin, inxhinierinë dhe programimin e orientuar drejt objektit gjendet në libër, dhe në kapitullin e tretë të librit mund të gjeni një përshkrim shumë të qartë të të gjitha aspekteve të orientuara nga objekti. gjuha Java.

Konceptet themelore të OOP

Programim i orientuar nga objekti ose OOP (programim i orientuar nga objekti) - metodologjia e programimit bazuar në paraqitjen e një programi si një koleksion objektesh, secila prej të cilave është një zbatim i një lloji të caktuar, duke përdorur një mekanizëm përcjellja e mesazheve dhe klasat e organizuara në hierarkia e trashëgimisë.

Elementi qendror i OOP është abstraksioni. Të dhënat shndërrohen në objekte duke përdorur abstraksionin, dhe sekuenca e përpunimit të këtyre të dhënave kthehet në një grup mesazhesh të kaluara midis këtyre objekteve. Secili prej objekteve ka sjelljen e tij unike. Objektet mund të trajtohen si entitete konkrete që i përgjigjen mesazheve që i urdhërojnë të kryejnë disa veprime.

OOP karakterizohet nga parimet e mëposhtme (sipas Alan Kay):

  • gjithçka është një objekt;
  • llogaritjet kryhen nëpërmjet ndërveprimit (shkëmbimit të të dhënave) ndërmjet objekteve, në të cilat një objekt kërkon që një objekt tjetër të kryejë një veprim; objektet ndërveprojnë duke dërguar dhe marrë mesazhe; një mesazh është një kërkesë për të kryer një veprim, i plotësuar nga një grup argumentesh që mund të nevojiten gjatë kryerjes së veprimit;
  • çdo objekt ka një të pavarur memorie, e cila përbëhet nga objekte të tjera;
  • çdo objekt është një përfaqësues i një klase që shpreh vetitë e përgjithshme të objekteve të një lloji të caktuar;
  • vendosur në klasë funksionalitetin(sjellja e objektit); kështu, të gjithë objektet që janë instanca të së njëjtës klasë mund të kryejnë të njëjtat veprime;
  • klasat organizohen në një strukturë të vetme peme me një rrënjë të përbashkët, të quajtur hierarkia e trashëgimisë; kujtesa dhe sjellja e lidhur me instancat e një klase të caktuar janë automatikisht të disponueshme për çdo klasë më të ulët në pemën hierarkike.

Përkufizimi 10.1. Abstraksioni- një metodë për zgjidhjen e një problemi në të cilin objektet e llojeve të ndryshme bashkohen nga një koncept (koncept) i përbashkët, dhe më pas entitetet e grupuara konsiderohen si elementë të një kategorie të vetme.

Abstraksioni ju lejon të ndani kuptimin logjik të një fragmenti programi nga problemi i zbatimit të tij, ndarjes përshkrim i jashtëm(ndërfaqja) e një objekti dhe e tij organizimi i brendshëm(zbatimi).

Përkufizimi 10.2. Kapsulimi- një teknikë në të cilën informacioni që është i parëndësishëm nga pikëpamja e ndërfaqes së objektit është i fshehur brenda tij.

Përkufizimi 10.3. Trashëgimia- një veti e objekteve përmes të cilave instancat e një klase fitojnë akses në të dhënat dhe metodat e klasave paraardhëse pa i ripërcaktuar ato.

Trashëgimia lejon lloje të ndryshme të dhënash të ndajnë të njëjtin kod, duke rezultuar në kod më të vogël dhe funksionalitet më të madh.

Përkufizimi 10.4.

Nuk di të programoj në gjuhë të orientuara nga objekti. Unë nuk mësova. Pas 5 vitesh programimi industrial në Java, unë ende nuk di si të krijoj një sistem të mirë në një stil të orientuar nga objekti. Unë thjesht nuk e kuptoj.

Unë u përpoqa të mësoja, sinqerisht. Studiova modele, lexova kodin e projekteve me burim të hapur, u përpoqa të ndërtoj koncepte koherente në kokën time, por ende nuk i kuptoja parimet e krijimit të programeve me cilësi të lartë të orientuar nga objekti. Ndoshta dikush tjetër i ka kuptuar, por jo unë.

Dhe këtu janë disa gjëra që më bëjnë konfuz.

Unë nuk e di se çfarë është OOP

Seriozisht. Është e vështirë për mua të formuloj idetë kryesore të OOP. Në programimin funksional, një nga idetë kryesore është pashtetësia. Në strukturore - dekompozim. Në modulare, funksionaliteti ndahet në blloqe të plota. Në secilën prej këtyre paradigmave, parimet mbizotëruese zbatohen në 95% të kodit dhe gjuha është krijuar për të inkurajuar përdorimin e tyre. Unë nuk di ndonjë rregull të tillë për OOP.
  • Abstraksioni
  • Kapsulimi
  • Trashëgimia
  • Polimorfizmi
Duket si një grup rregullash, apo jo? Pra, këto janë rregullat që duhen ndjekur në 95% të rasteve? Hmm, le të hedhim një vështrim më të afërt.

Abstraksioni

Abstraksioni është një mjet i fuqishëm programimi. Kjo është ajo që na lejon të ndërtojmë sisteme të mëdha dhe të mbajmë kontrollin mbi to. Nuk ka gjasa që do t'i kishim afruar ndonjëherë nivelit të sotëm të programeve nëse nuk do të ishim të armatosur me një mjet të tillë. Megjithatë, si lidhet abstraksioni me OOP?

Së pari, abstraksioni nuk është një atribut ekskluzivisht i OOP, ose i programimit në përgjithësi. Procesi i krijimit të niveleve të abstraksionit shtrihet pothuajse në të gjitha fushat e njohurive njerëzore. Kështu, ne mund të bëjmë gjykime për materialet pa hyrë në detajet e strukturës së tyre molekulare. Ose flisni për objekte pa përmendur materialet nga të cilat janë bërë. Ose flisni për mekanizma komplekse, të tilla si një kompjuter, një turbinë avioni ose trupin e njeriut, pa kujtuar detajet individuale të këtyre entiteteve.

Së dyti, ka pasur gjithmonë abstraksione në programim, duke filluar nga shkrimet e Ada Lovelace, e cila konsiderohet si programuesja e parë në histori. Që atëherë, njerëzit kanë krijuar vazhdimisht abstraksione në programet e tyre, shpesh vetëm me mjetet më të thjeshta për këtë. Kështu, Abelson dhe Sussman, në librin e tyre të njohur, përshkruajnë se si të krijohet një sistem për zgjidhjen e ekuacioneve që mbështet numrat kompleks dhe madje edhe polinomet, duke përdorur vetëm procedura dhe lista të lidhura. Pra, çfarë mjetesh shtesë të abstraksionit ofron OOP? Unë nuk kam asnjë ide. Po ndahet kodi në nënprograme? Çdo gjuhë e nivelit të lartë mund ta bëjë këtë. Kombinoni rutinat në një vend? Ka mjaft module për këtë. Tipizimi? Ajo ekzistonte shumë kohë përpara PLO. Shembulli me një sistem për zgjidhjen e ekuacioneve tregon qartë se ndërtimi i niveleve të abstraksionit varet jo aq nga mjetet gjuhësore, por nga aftësitë e programuesit.

Kapsulimi

Avantazhi kryesor i kapsulimit është fshehja e zbatimit. Kodi i klientit sheh vetëm ndërfaqen dhe mund të mbështetet vetëm në të. Kjo liron zhvilluesit që mund të vendosin të ndryshojnë zbatimin. Dhe kjo është vërtet e lezetshme. Por pyetja përsëri është, çfarë ka të bëjë OOP me të? Të gjitha Paradigmat e mësipërme përfshijnë fshehjen e zbatimit. Kur programoni në C, ju shpërndani ndërfaqen në skedarët e kokës, Oberon ju lejon të bëni fushat dhe metodat lokale në modul dhe së fundi, abstraksioni në shumë gjuhë ndërtohet thjesht përmes nënprogrameve që gjithashtu përmbledhin zbatimin. Për më tepër, gjuhët e orientuara nga objekti janë shpesh vetë shkelin rregullin e kapsulimit, duke siguruar qasje në të dhëna përmes metodave speciale - getters dhe setters në Java, pronat në C#, etj. (Në komentet zbuluam se disa objekte në gjuhët e programimit nuk janë objekte nga pikëpamja OOP: objektet e transferimit të të dhënave janë përgjegjëse vetëm për transferimin e të dhënave, dhe për këtë arsye nuk janë entitete OOP me të drejta të plota, dhe për këtë arsye nuk ka nevoja që ato të ruajnë kapsulimin. Nga ana tjetër, metodat aksesore ruhen më së miri për të ruajtur fleksibilitetin arkitektonik. Kështu bëhet e ndërlikuar.) Për më tepër, disa gjuhë të orientuara nga objekti, si Python, nuk përpiqen të fshehin asgjë fare. , por mbështetuni vetëm në inteligjencën e zhvilluesve që përdorin kodin.

Trashëgimia

Trashëgimia është një nga gjërat e pakta të reja që vërtet doli në skenë falë OOP. Jo, gjuhët e orientuara nga objekti nuk krijuan një ide të re - trashëgimia mund të zbatohet në çdo paradigmë tjetër - por OOP për herë të parë e solli këtë koncept në nivelin e vetë gjuhës. Përparësitë e trashëgimisë janë gjithashtu të dukshme: kur ju pothuajse të kënaqur me një klasë, mund të krijoni një pasardhës dhe të anashkaloni një pjesë të funksionalitetit të tij. Në gjuhët që mbështesin trashëgiminë e shumëfishtë, si C++ ose Scala (në këtë të fundit, përmes tipareve), shfaqet një rast tjetër përdorimi - mixins, klasa të vogla që ju lejojnë të "përzieni" funksionalitetin në një klasë të re pa kopjuar kodin.

Pra, kjo është ajo që e veçon OOP si një paradigmë nga të tjerët? Hmm... nëse po, pse e përdorim kaq rrallë në kod real? E mbani mend atë që thashë për 95% të kodit që u bindet rregullave të paradigmës dominuese? Nuk po bëja shaka. Në programimin funksional, të paktën 95% e kodit përdor të dhëna dhe funksione të pandryshueshme pa efekte anësore. Në modular, pothuajse i gjithë kodi është i paketuar logjikisht në module. Përkrahësit e programimit të strukturuar, duke ndjekur parimet e Dijkstra-s, përpiqen t'i ndajnë të gjitha pjesët e programit në pjesë të vogla. Trashëgimia përdoret shumë më rrallë. Ndoshta në 10% të kodit, ndoshta në 50%, në disa raste (për shembull, kur trashëgoni nga klasat e kornizës) - në 70%, por jo më shumë. Sepse në shumicën e situatave është e lehtë nuk ka nevojë.

Për më tepër, trashëgimia e rrezikshme për dizajn të mirë. Aq e rrezikshme sa Banda e Katërve (në dukje predikues të PLO) në librin e tyre rekomandojnë zëvendësimin e saj me delegim sa herë që është e mundur. Trashëgimia siç ekziston në gjuhët aktualisht të njohura çon në dizajn të brishtë. Pasi është trashëguar nga një paraardhës, një klasë nuk mund të trashëgohet më nga të tjerët. Ndryshimi i një paraardhësi gjithashtu bëhet i rrezikshëm. Ka, sigurisht, modifikues privatë/të mbrojtur, por ata gjithashtu kërkojnë aftësi të konsiderueshme psikike për të gjetur se si mund të ndryshojë klasa dhe si mund ta përdorë atë kodi i klientit. Trashëgimia është aq e rrezikshme dhe e papërshtatshme sa korniza të mëdha (siç janë Spring dhe EJB në Java) po e braktisin atë në favor të mjeteve të tjera jo të orientuara nga objekti (për shembull, metaprogramimi). Pasojat janë aq të paparashikueshme saqë disa biblioteka (të tilla si Guava) caktojnë modifikues në klasat e tyre që ndalojnë trashëgiminë dhe në gjuhën e re Go u vendos që të braktiset fare hierarkia e trashëgimisë.

Polimorfizmi

Ndoshta polimorfizmi është gjëja më e mirë për programimin e orientuar nga objekti. Falë polimorfizmit, kur del, një objekt i tipit Person duket si "Shandorkin Adam Impolitovich", dhe një objekt i tipit Point duket si "". Është kjo që ju lejon të shkruani "Mat1 * Mat2" dhe të merrni produktin e matricave, të ngjashëm me produktin e numrave të zakonshëm. Pa të, nuk do të ishte e mundur të lexoheshin të dhënat nga rryma hyrëse, pa u kujdesur nëse ato vijnë nga rrjeti, një skedar ose një linjë në memorie. Kudo që ka ndërfaqe, nënkuptohet edhe polimorfizmi.

Më pëlqen shumë polimorfizmi. Prandaj, nuk do të flas as për problemet e tij në gjuhët kryesore. Unë gjithashtu do të hesht për ngushtësinë e qasjes së dërgimit vetëm sipas llojit dhe se si mund të bëhet kjo. Në shumicën e rasteve funksionon siç duhet, gjë që nuk është keq. Pyetja është: a është polimorfizmi vetë parimi që e dallon OOP nga paradigmat e tjera? Nëse do të më kishit pyetur mua (dhe duke qenë se po e lexoni këtë tekst, mund të supozoni se keni pyetur), unë do të përgjigjesha "jo". Dhe arsyeja është ende e njëjta përqindje e përdorimit në kod. Ndoshta ndërfaqet dhe metodat polimorfike janë pak më të zakonshme se trashëgimia. Por krahasoni numrin e rreshtave të kodit që ata zënë me numrin e rreshtave të shkruar në stilin e zakonshëm procedural - ka gjithmonë më shumë nga këto të fundit. Duke parë gjuhët që inkurajojnë këtë stil programimi, nuk do t'i quaja polimorfike. Gjuhët që mbështesin polimorfizmin - po, kjo është normale. Por jo gjuhë polimorfike.

(Megjithatë, ky është mendimi im. Gjithmonë mund të mos pajtoheni.)

Pra, abstraksioni, kapsulimi, trashëgimia dhe polimorfizmi - e gjithë kjo është në OOP, por asnjë nga këto nuk është një atribut integral i saj. Atëherë çfarë është OOP? Ekziston një mendim se thelbi i programimit të orientuar nga objekti qëndron në objekte (tingëllon mjaft logjike) dhe klasa. Është ideja e kombinimit të kodit dhe të dhënave, dhe ideja që objektet në një program pasqyrojnë entitete në botën reale. Ne do t'i kthehemi këtij mendimi më vonë, por së pari le të vendosim disa i.

OOP i kujt është më i freskët?

Nga pjesa e mëparshme është e qartë se gjuhët e programimit mund të ndryshojnë shumë në mënyrën se si zbatojnë programimin e orientuar nga objekti. Nëse merrni tërësinë e të gjitha zbatimeve të OOP në të gjitha gjuhët, atëherë ka shumë të ngjarë që nuk do të gjeni një veçori të vetme të përbashkët për të gjitha. Për të kufizuar disi këtë kopsht zoologjik dhe për të sqaruar arsyetimin, do të përqendrohem vetëm në një grup - gjuhët thjesht të orientuara nga objekti, përkatësisht Java dhe C#. Termi "thjesht i orientuar nga objekti" në këtë rast do të thotë që gjuha nuk mbështet paradigma të tjera ose i zbaton ato përmes të njëjtit OOP. Python ose Ruby, për shembull, nuk do të jenë të pastër, sepse ju lehtë mund të shkruani një program të plotë mbi to pa një deklaratë të vetme klase.

Për të kuptuar më mirë thelbin e OOP në Java dhe C#, le të shohim shembuj të zbatimit të kësaj paradigme në gjuhë të tjera.

Muhabet. Ndryshe nga homologët e saj modernë, kjo gjuhë u shtyp në mënyrë dinamike dhe përdori një stil të kalimit të mesazheve për të zbatuar OOP. Në vend të thirrjes së metodave, objektet i dërgonin mesazhe njëri-tjetrit dhe nëse marrësi nuk mund të përpunonte atë që vinte, ai thjesht ia përcjell mesazhin dikujt tjetër.

Lisp e zakonshme. Fillimisht, CL ndoqi të njëjtën paradigmë. Më pas zhvilluesit vendosën që shkrimi "(send obj "some-message)" ishte shumë i gjatë dhe e konvertuan shënimin në një thirrje metode - `(disome-metod obj)` Sot, Common Lisp ka një sistem programimi të pjekur të orientuar nga objekti ( CLOS) me mbështetje për trashëgimi të shumëfishtë, multimetoda dhe metaklasa. Një tipar dallues është se OOP në CL nuk rrotullohet rreth objekteve, por rreth funksioneve gjenerike.

Clojure. Clojure ka dy sisteme programimi të orientuara nga objekti - një i trashëguar nga Java, dhe i dyti, i bazuar në multimetoda dhe më shumë i ngjashëm me CLOS.

R. Kjo gjuhë për analizën e të dhënave statistikore ka gjithashtu 2 sisteme programimi të orientuara drejt objekteve - S3 dhe S4. Të dyja janë trashëguar nga gjuha S (gjë që nuk është për t'u habitur, duke pasur parasysh se R është një zbatim me kod të hapur i S komercial). S4 përputhet kryesisht me implementimet OOP në gjuhët moderne të zakonshme. S3 është një opsion më i lehtë, i zbatuar thjesht duke përdorur vetë gjuhën: krijohet një funksion i përgjithshëm që dërgon kërkesat bazuar në atributin "klasë" të objektit të marrë.

JavaScript. Ideologjikisht i ngjashëm me Smalltalk, megjithëse përdor një sintaksë të ndryshme. Në vend të trashëgimisë, ai përdor prototipin: nëse vetia e dëshiruar ose metoda e thirrur nuk është në vetë objektin, atëherë kërkesa i kalohet objektit prototip (vetia e prototipit të të gjitha objekteve JavaScript). Një fakt interesant është se sjellja e të gjitha objekteve të klasës mund të ndryshohet duke zëvendësuar një nga metodat prototip (për shembull, shtimi i metodës `.toBASE64` për klasën string duket shumë bukur).

Python. Në përgjithësi, ai ndjek të njëjtin koncept si gjuhët kryesore, por gjithashtu mbështet kalimin e kërkimit të atributeve në një objekt tjetër, si në JavaScript ose Smalltalk.

Haskell. Në Haskell nuk ka fare gjendje, dhe për këtë arsye nuk ka objekte në kuptimin e zakonshëm. Sidoqoftë, ekziston ende një lloj OOP atje: llojet e të dhënave mund t'i përkasin një ose më shumë klasave të tipit. Për shembull, pothuajse të gjitha llojet në Haskell janë në klasën Eq (përgjegjës për operacionet e krahasimit midis 2 objekteve), dhe të gjithë numrat janë gjithashtu në klasat Num (veprimet mbi numrat) dhe Ord (veprimet mbi numrat).<, <=, >=, >). Në gjuhët menstruale, llojet korrespondojnë me klasat (të dhënat), dhe klasat e tipit korrespondojnë me ndërfaqet.

Shtet apo pa shtetësi?

Por le të kthehemi te sistemet më të zakonshme të programimit të orientuar drejt objektit. Ajo që nuk mund ta kuptoja kurrë është marrëdhënia e objekteve me gjendjen e brendshme. Përpara se të studioja OOP, gjithçka ishte e thjeshtë dhe transparente: ka struktura që ruajnë disa të dhëna të lidhura, ka procedura (funksione) që i përpunojnë ato. ec (qen), tërheq (llogari, shuma). Pastaj erdhën objektet, dhe kjo ishte gjithashtu në rregull (megjithëse leximi i programeve u bë shumë më i vështirë - qeni im po ecte [kush?], dhe llogaria po tërhiqte para [nga ku?]). Pastaj mësova për fshehjen e të dhënave. Unë ende mund ta shëtisja qenin, por nuk mund të shikoja më përbërjen e ushqimit të tij. Ushqimi nuk bëri asgjë (ju ndoshta mund të shkruani food.eat(qen), por unë ende preferoj që qeni im të hajë ushqim dhe jo anasjelltas). Ushqimi është vetëm të dhëna, dhe unë (dhe qeni im) thjesht duhej t'i qasja. Të gjitha Vetëm. Por nuk ishte më e mundur të futej në kornizën e paradigmës, si në xhinse të vjetra nga fundi i viteve '90.

Mirë, ne kemi metoda të aksesit të të dhënave. Le të kënaqemi me këtë vetë-mashtrim të vogël dhe të pretendojmë se të dhënat tona janë vërtet të fshehura. Por tani e di që objektet janë, para së gjithash, të dhëna, dhe më pas, ndoshta, metoda që i përpunojnë ato. Kuptova se si të shkruaja programe, për çfarë të përpiqesha gjatë dizajnimit.

Përpara se të kisha kohë për të shijuar ndriçimin, pashë fjalën pa shtetësi në internet (të betohem se ishte e rrethuar nga shkëlqimi dhe një aureolë varej mbi shkronjat t dhe l). Një studim i shkurtër i literaturës zbuloi botën e mrekullueshme të rrjedhës së kontrollit transparent dhe multithreading-ut të thjeshtë pa nevojën për të gjurmuar konsistencën e objektit. Sigurisht, menjëherë doja të prekja këtë botë të mrekullueshme. Sidoqoftë, kjo nënkuptonte një refuzim të plotë të çdo rregulli - tani nuk ishte e qartë nëse qeni duhet të ecte vetë, apo nëse ishte i nevojshëm një Menaxher i veçantë Walk për këtë; a keni nevojë për një llogari, apo do të merret Banka me të gjitha punët, dhe nëse po, a duhet t'i shlyejë paratë në mënyrë statike apo dinamike, etj. Numri i rasteve të përdorimit është rritur në mënyrë eksponenciale dhe të gjitha rastet e përdorimit të ardhshëm mund të çojnë në nevojën për rifaktorim të madh.

Unë ende nuk e di se kur një objekt duhet të bëhet pa shtetësi, kur duhet të jetë i gjendjes dhe kur duhet të jetë thjesht një kontejner të dhënash. Ndonjëherë është e qartë, por në shumicën e rasteve nuk është.

Shtypja: statike apo dinamike?

Një gjë tjetër që nuk mund të vendos për gjuhët si C# dhe Java është nëse ato janë të shtypura në mënyrë statike apo dinamike. Shumica e njerëzve ndoshta do të thërrasin: “Çfarë marrëzie! Natyrisht i shtypur në mënyrë statike! Llojet kontrollohen në kohën e përpilimit! Por a është vërtet kaq e thjeshtë? A është e vërtetë që duke specifikuar tipin X në parametrat e një metode, një programues mund të jetë i sigurt se objektet e tipit X do t'i kalohen gjithmonë atij? Kjo është e drejtë - nuk mundet, sepse ... do të jetë e mundur të kalohet një parametër i tipit X në metodën X ose trashëgimtari i tij. Do të duket, pra çfarë? Pasardhësit e klasës X do të kenë ende të njëjtat metoda si X. Metodat janë metoda, por logjika e punës mund të dalë krejtësisht e ndryshme. Rasti më i zakonshëm është kur një klasë fëmijë rezulton të jetë e optimizuar për nevoja të tjera përveç X, dhe metoda jonë mund të mbështetet pikërisht në atë optimizim (nëse një skenar i tillë ju duket jorealist, provoni të shkruani një shtojcë për një bibliotekë të zhvilluar me burim të hapur - ose do të shpenzoni disa javë për të analizuar arkitekturën dhe algoritmet e bibliotekës, ose thjesht do të thërrisni metoda me një nënshkrim të përshtatshëm rastësisht). Si rezultat, programi funksionon, por shpejtësia e funksionimit bie me një rend të madhësisë. Edhe pse nga këndvështrimi i përpiluesit gjithçka është e saktë. Është domethënëse që Scala, e cila quhet pasardhëse e Java-s, në shumë vende si parazgjedhje lejon që të kalohen vetëm argumentet e llojit të specifikuar, megjithëse kjo sjellje mund të ndryshohet.

Një problem tjetër është vlera null, e cila mund të kalohet në vend të pothuajse çdo objekti në Java dhe në vend të çdo objekti Nullable në C#. null u përket të gjitha llojeve në të njëjtën kohë, dhe në të njëjtën kohë nuk i përket asnjërit. null nuk ka as fusha as metoda, kështu që çdo thirrje në të (përveç kontrollit për null) rezulton në një gabim. Duket se të gjithë janë mësuar me këtë, por për krahasim, Haskell (dhe e njëjta Scala) është e detyruar të përdorë lloje të veçanta (Ndoshta në Haskell, Option në Scala) për të mbështjellë funksione që në gjuhë të tjera mund të kthejnë nule. Si rezultat, ata shpesh thonë për Haskell "është e vështirë të përpilosh një program në të, por nëse ke sukses, atëherë ka shumë të ngjarë që ai të funksionojë siç duhet".

Nga ana tjetër, gjuhët e zakonshme nuk janë të shtypura në mënyrë dinamike, dhe për këtë arsye nuk kanë veti të tilla si ndërfaqe të thjeshta dhe procedura fleksibël. Si rezultat, të shkruarit në stilin Python ose Lisp gjithashtu bëhet i pamundur.

Çfarë ndryshimi ka si quhet ky shtypje nëse dihen gjithsesi të gjitha rregullat? Dallimi është se nga cila anë i afroheni dizajnit të arkitekturës. Ekziston një debat i gjatë se si të ndërtohet një sistem: të bëhen shumë lloje dhe pak funksione, apo pak lloje dhe shumë funksione? Qasja e parë përdoret në mënyrë aktive në Haskell, e dyta në Lisp. Gjuhët moderne të orientuara nga objekti përdorin diçka në mes. Nuk dua të them se kjo është e keqe - ndoshta ka avantazhet e saj (në fund të fundit, nuk duhet të harrojmë se Java dhe C# janë platforma shumë-gjuhëshe), por sa herë që filloj një projekt të ri pyes veten se ku të filloj projektim - me lloje ose nga funksionaliteti.

Dhe më tej...

Nuk di si ta modeloj problemin. Besohet se OOP ju lejon të shfaqni objekte të botës reale në një program. Sidoqoftë, në realitet unë kam një qen (me dy veshë, katër putra dhe një jakë) dhe një llogari bankare (me një menaxher, nëpunës dhe një pushim dreke), dhe në program - WalkManager, AccountFactory ... mirë, ju merrni Ideja. Dhe çështja nuk është se programi ka klasa ndihmëse që nuk pasqyrojnë objekte të botës reale. Fakti është se kontrolloni ndryshimet e rrjedhës. WalkingManager po më grabit gëzimin e shëtitjes së qenit tim dhe unë marr para nga një llogari bankare pa shpirt (hej, ku është ajo vajza e lezetshme që kam ndërruar para javën e kaluar?).

Ndoshta unë jam snob, por isha shumë më i lumtur kur të dhënat në kompjuter ishin vetëm të dhëna, edhe nëse përshkruanin qenin tim ose një llogari bankare. Mund të bëja atë që ishte e përshtatshme me të dhënat, pa marrë parasysh botën reale.

Unë gjithashtu nuk e di se si ta zbërthej siç duhet funksionalitetin. Në Python ose C++, nëse më duhej një funksion i vogël për të kthyer një varg në një numër, unë thjesht e shkrova atë në fund të skedarit. Në Java ose C# jam i detyruar ta vendos në një klasë të veçantë StringUtils. Në gjuhët para-OO, mund të deklaroja një mbështjellës ad hoc për të kthyer dy vlera nga një funksion (shuma e tërhequr dhe bilanci i llogarisë). Në gjuhët OOP, do të më duhet të krijoj një klasë të plotë të Rezultateve të Transaksionit. Dhe për një person të ri në projekt (ose edhe për veten time një javë më vonë), kjo klasë do të duket po aq e rëndësishme dhe themelore në arkitekturën e sistemit. 150 skedarë, dhe të gjithë po aq të rëndësishëm dhe themelorë - oh po, arkitekturë transparente, nivele të mrekullueshme abstraksioni.

Nuk di të shkruaj programe efikase. Programet efikase përdorin pak memorie - përndryshe mbledhësi i mbeturinave do të ngadalësojë vazhdimisht ekzekutimin. Por për të kryer operacionin më të thjeshtë në gjuhët e orientuara nga objekti, duhet të krijoni një duzinë objektesh. Për të bërë një kërkesë HTTP, më duhet të krijoj një objekt të tipit URL, më pas një objekt të tipit HttpConnection, më pas një objekt të tipit Kërkesë... mirë, e kuptoni idenë. Në programimin procedural, unë thjesht do të quaj disa procedura, duke i kaluar atyre një strukturë të krijuar në stack. Me shumë mundësi, vetëm një objekt do të krijohej në memorie - për të ruajtur rezultatin. Në OOP, më duhet të rrëmoj kujtesën gjatë gjithë kohës.

Ndoshta OOP është një paradigmë vërtet e bukur dhe elegante. Ndoshta nuk jam aq i zgjuar sa ta kuptoj. Ndoshta ka dikush atje që mund të krijojë një program vërtet të bukur në një gjuhë të orientuar nga objekti. Epo, unë vetëm mund t'i kem zili.



Artikuj të ngjashëm: