Si të konfiguroni telefonat inteligjentë dhe PC. Portali informativ
  • në shtëpi
  • Windows 8
  • Laboratorët e informatikës, provimi. Parimet e programimit të orientuar drejt objekteve

Laboratorët e informatikës, provimi. Parimet e programimit të orientuar drejt objekteve

(siç nënkupton OOP) është, para së gjithash, një paradigmë programimi.
Paradigma e programimit përcakton se si programuesi e sheh ekzekutimin e programit.
Pra, për paradigmën OOP, është karakteristikë që programuesi e konsideron programin si një grup objektesh ndërvepruese, ndërsa, për shembull, në programimin funksional, programi përfaqësohet si një sekuencë llogaritje funksionesh. Programimi procedural, ose, siç quhet edhe saktë, operacional klasik, nënkupton shkrimin e një algoritmi për zgjidhjen e një problemi; megjithatë, vetitë e pritshme të rezultatit përfundimtar nuk përshkruhen ose tregohen. Programimi i strukturuar në thelb i përmbahet të njëjtave parime si programimi procedural, duke i plotësuar ato vetëm pak me truke të dobishme.
Paradigmat e programimit joprocedural, të cilat përfshijnë paradigmën e orientuar nga objekti, kanë ide krejtësisht të ndryshme.
Përkufizimi i Gradi Buch është: Programim i orientuar nga objektiËshtë një metodologji programimi që bazohet në paraqitjen e një programi si një grup objektesh, secila prej të cilave është një zbatim i një klase të caktuar (lloj i një lloji të veçantë), dhe klasat formojnë një hierarki bazuar në parimet e trashëgimisë ".
Programimi strukturor dhe i orientuar nga objekti bazohet në një metodë të tillë shkencore si dekompozimi- një metodë që përdor strukturën e problemit dhe ju lejon të ndani zgjidhjen e një problemi të përbashkët të madh në zgjidhjen e një sekuence problemesh më të vogla. Zbërthimi i OOP ndodh jo sipas algoritmeve, por sipas objekteve të përdorura për të zgjidhur problemin. Ky zbërthim zvogëlon madhësinë e sistemeve softuerike duke ripërdorur mekanizma të zakonshëm. Dihet se sistemet e programimit vizual ose sistemet e bazuara në parimet e programimit të orientuar nga objekti janë më fleksibël dhe më të lehtë për t'u zhvilluar me kalimin e kohës.

Historia e zhvillimit të OOP daton në fund të viteve '60. Gjuha e parë e orientuar nga objekti ishte gjuha e programimit Simula, e krijuar në një qendër kompjuterike në Norvegji. Gjuha kishte për qëllim të simulonte situata të botës reale. Një tipar i Simula ishte se një program i shkruar në një gjuhë organizohej nga objekte programuese. Objektet kishin udhëzime të quajtura metoda dhe të dhëna të quajtura variabla; metodat dhe të dhënat përcaktuan sjelljen e objektit. Gjatë procesit të modelimit, objekti u soll sipas sjelljes së tij standarde dhe, nëse ishte e nevojshme, ndryshoi të dhënat për të pasqyruar ndikimin e veprimit të caktuar.

Ka mjaftueshëm gjuhë programimi të orientuara nga objekti, më të njohurat prej të cilave janë aktualisht C ++, Delphi, Java, Visual Basic, Flash. Por, përveç kësaj, shumë gjuhë që zakonisht konsiderohen si një paradigmë procedurale kanë gjithashtu veti OOP, duke qenë në gjendje të punojnë me objekte. Pra, programimi i orientuar nga objekti në C është një pjesë e madhe e programimit në këtë gjuhë, e njëjta gjë vlen edhe për OOP në python dhe shumë gjuhë të tjera të strukturuara.

Kur flasim për OOP, shpesh del një përkufizim tjetër - programimi vizual... Ai gjithashtu siguron përdorim të gjerë të prototipave të objekteve, të cilat përcaktohen si klasa objektesh.
Zhvillimet. Në shumë mjedise programimi vizual, zbatohet një karakteristikë (përveç kapsulimit, polimorfizmit dhe trashëgimisë) e një objekti - një ngjarje. Ngjarjet në programimin e orientuar nga objekti është aftësia për të përpunuar të ashtuquajturat mesazhe (ose ngjarje) të marra nga sistemi operativ Windows ose vetë programi. Ky parim është tipik për të gjithë komponentët e mjedisit që përpunojnë ngjarje të ndryshme që ndodhin gjatë ekzekutimit të programit. Në fakt, një ngjarje është një lloj veprimi që aktivizon reagimin standard të një objekti. Një ngjarje mund të konsiderohet, për shembull, klikimi në butonin e miut, vendosja e kursorit të miut mbi një artikull të menysë, hapja e një skede, etj. Rendi i ekzekutimit të veprimeve të caktuara përcaktohet pikërisht nga ngjarjet që ndodhin në sistem dhe reagimi i objekteve ndaj tyre.
Klasat dhe objektet në OOP- koncepte të ndryshme. Koncepti i një klase në OOP është një lloj i të dhënave (i njëjtë si, për shembull, Real ose String), dhe një objekt është një shembull konkret i një klase (kopja e saj), e ruajtur në memorien e kompjuterit si një ndryshore e llojit përkatës. .
Klasaështë një lloj i strukturuar i të dhënave. Klasa përfshin një përshkrim të fushave të të dhënave, si dhe procedurat dhe funksionet që punojnë me këto fusha të dhënash. Metoda OOP- këto janë procedura dhe funksione të tilla në lidhje me klasat.
Klasat kanë fusha (si tipi i të dhënave të regjistrimit), veti që janë të ngjashme me fushat, por kanë përshkrues shtesë që përcaktojnë mekanizmat për shkrimin dhe leximin e të dhënave dhe metodave - nënprograme që synojnë ndryshimin e fushave dhe vetive të një klase.

Parimet themelore të OOP

Përveç trajtimit të ngjarjeve, parimet e programimit të orientuar nga objekti janë kapsulimi, trashëgimia, nënklasifikimi dhe polimorfizmi. Ato janë veçanërisht të dobishme dhe thelbësore kur zhvillohen aplikacione të riprodhueshme dhe të lehta për t'u mirëmbajtur.
Një objekt kombinon metoda dhe veti që nuk mund të ekzistojnë veçmas prej tij. Prandaj, nëse objekti fshihet, atëherë vetitë e tij dhe metodat e lidhura fshihen. Kur kopjoni, ndodh e njëjta gjë: objekti kopjohet në tërësi. kapsulimi OOP- kjo është karakteristika e përshkruar.

Parimi i trashëgimisë OOP dhe nënklasat

Absolutisht të gjitha objektet krijohen në bazë të klasave, ndërsa trashëgojnë vetitë dhe metodat e këtyre klasave. Nga ana tjetër, klasat mund të krijohen bazuar në klasa të tjera (prindër), atëherë klasa të tilla quhen nënklasa (pasardhës). Nënklasat trashëgojnë të gjitha vetitë dhe metodat e klasës mëmë. Përveç kësaj, për një nënklasë ose një klasë pasardhëse, ju mund të përcaktoni vetitë dhe metodat tuaja të reja, si dhe të ndryshoni metodat e klasës mëmë. Ndryshimet në vetitë dhe metodat e një klase mëmë gjurmohen në nënklasat e bazuara në këtë klasë, si dhe në objektet e krijuara nga nënklasat. Kjo është trashëgimi OOP.

Polimorfizmi OOP

Në programimin e orientuar nga objekti, polimorfizmi karakterizohet si ndërkëmbueshmëria e objekteve me të njëjtën ndërfaqe. Kjo mund të shpjegohet si më poshtë: klasa pasardhëse trashëgon instancat e metodave të klasës mëmë, por ekzekutimi i këtyre metodave mund të ndodhë në një mënyrë tjetër, që korrespondon me specifikat e klasës pasardhëse, domethënë të modifikuar.
Kjo do të thotë, nëse në programimin procedural emri i një procedure ose funksioni identifikon në mënyrë unike kodin e ekzekutueshëm të lidhur me një procedurë ose funksion të caktuar, atëherë në programimin e orientuar nga objekti mund të përdorni të njëjtat emra metodash për të kryer veprime të ndryshme. Domethënë, rezultati i ekzekutimit të së njëjtës metodë varet nga lloji i objektit në të cilin aplikohet kjo metodë.

Faqja paraqet një teori të pjesshme të programimit të orientuar nga objekti për fillestarët dhe shembuj OOP të zgjidhjes së problemeve. Mësimet e faqes OOP janë algoritme të detajuara për detyrën. Në bazë të kryerjes së këtyre punëve laboratorike, studenti do të jetë në gjendje të zgjidhë në mënyrë të pavarur probleme të tjera të ngjashme në të ardhmen.
Ne ju dëshirojmë një mësim të lehtë dhe argëtues rreth programimit të orientuar nga objekti!

Karakteristikat dalluese të OOP

1) Qasja OO fokusohet në të dhënat si elementët më të qëndrueshëm të një sistemi kompjuterik

2) Qasja OO ju lejon të zhvilloni kodin e programit që synon përdorimin e përsëritur

3) Qasja OO siguron shkallëzim më të mirë në projektet softuerike, d.m.th. krijimi i programeve me shkallë të ndryshme kompleksiteti, prandaj, shumica e teknologjive moderne të projektimit përfshijnë përdorimin e OOP.

Në teorinë e programimit OO, një qasje përkufizohet si një teknologji për krijimin e softuerit kompleks, cat. Bazuar në paraqitjen e një programi si një koleksion i objekteve softuerike. Avantazhi kryesor i OOP është zvogëlimi i numrit të thirrjeve ndër-module dhe zvogëlimi i sasisë së informacionit të transferuar ndërmjet moduleve, krahasuar me programimin modular. Kjo arrihet për shkak të një lokalizimi më të plotë të të dhënave dhe integrimit të tyre me rutinat e përpunimit, gjë që lejon zhvillimin pothuajse të pavarur të pjesëve (objekteve) individuale të programit.

Për më tepër, qasja e objektit ofron mjete të reja të zhvillimit teknologjik, si trashëgimia, polimorfizmi, kompozimi, mbushja, duke ju lejuar të ndërtoni objekte më komplekse nga ato më të thjeshta. Rezultati është një rritje e konsiderueshme e ripërdorimit të kodit, aftësia për të krijuar biblioteka objektesh për aplikacione të ndryshme dhe mundësi shtesë për zhvilluesit për të krijuar sisteme me kompleksitet të shtuar.

OOP bazohet në sa vijon parimet:

1) abstragimi;

2) kufizimi i aksesit;

3) modulariteti;

4) hierarkia;

5) shtypja;

6) paralelizmi;

7) qëndrueshmëri.

Le të sqarojmë se cili është secili parim.

Abstraksioni- procesi i nxjerrjes në pah të abstraksioneve në fushën lëndore të problemit. Abstraksioniështë një grup karakteristikash thelbësore të një objekti që e dallojnë atë nga të gjitha llojet e tjera të objekteve dhe, në këtë mënyrë, përcaktojnë qartë tiparet e këtij objekti nga pikëpamja e shqyrtimit dhe analizës së mëtejshme. Në përputhje me përkufizimin, abstraksioni i aplikuar i një objekti real në thelb varet nga problemi që zgjidhet: në një rast do të na interesojë forma e objektit, në tjetrin pesha, në të tretën - materialet nga të cilat ai është bërë, në të katërtën - ligji i lëvizjes së objektit, etj. Niveli modern i abstraksionit presupozon unifikimin e të gjitha vetive të abstraksionit (si në lidhje me gjendjen e objektit të analizuar ashtu edhe me përcaktimin e sjelljes së tij) në një njësi të vetme programore, të caktuar. lloji abstrakt(Klasa).

Kufizimi i aksesit(Enkapsulimi është parimi që çdo klasë duhet të konsiderohet si një kuti e zezë - përdoruesi i klasës duhet të shohë dhe të përdorë vetëm pjesën e ndërfaqes së klasës (d.m.th., listën e vetive dhe metodave të deklaruara të klasës) dhe të mos gërmojë. në zbatimin e tij të brendshëm. Prandaj, është e zakonshme që të dhënat në një klasë të inkapsulohen në atë mënyrë që qasja në to për lexim ose shkrim të kryhet jo drejtpërdrejt, por me ndihmën e metodave. Parimi i kapsulimit (teorikisht) ju lejon për të minimizuar numrin e lidhjeve ndërmjet klasave dhe, në përputhje me rrethanat, për të thjeshtuar zbatimin dhe modifikimin e pavarur të klasave.) Kjo është fshehja e elementeve individuale të abstraksionit të zbatimit që nuk ndikon në karakteristikat e tij thelbësore në tërësi.


Nevoja për të kufizuar aksesin nënkupton një dallim midis dy pjesëve në përshkrimin e një abstraksioni:

a) ndërfaqe- një grup elementësh të aksesueshëm nga jashtë të zbatimit të abstraksionit (karakteristikat kryesore të gjendjes dhe sjelljes);

b) realizimi- një grup elementësh të paarritshëm nga jashtë për zbatimin e abstraksionit (organizimi i brendshëm i abstraksionit dhe mekanizmat për zbatimin e sjelljes së tij).

Kufizimi i aksesit në OOP lejon një zhvillues të:

1) të kryejë ndërtimin e sistemit në faza, pa u hutuar nga veçoritë e zbatimit të abstraksioneve të përdorura;

2) është e lehtë të modifikohet zbatimi i objekteve individuale, të cilat në një sistem të organizuar siç duhet nuk kërkojnë ndryshime në objekte të tjera.

Kombinimi i kombinimit të të gjitha vetive të një objekti (që përbëjnë gjendjen dhe sjelljen e tij) në një abstraksion të vetëm dhe kufizimin e aksesit në zbatimin e këtyre vetive quhet kapsulat .

Modulariteti- ky është parimi i zhvillimit të një sistemi softuerik, i cili nënkupton zbatimin e tij në formën e pjesëve (moduleve) të veçanta. Kur zbërthehet një sistem në module, është e dëshirueshme të kombinohen pjesët e lidhura logjikisht, duke siguruar sa më shumë që të jetë e mundur një reduktim të numrit të lidhjeve të jashtme midis moduleve. Parimi është trashëguar nga programimi modular, ndjekja e tij thjeshton dizajnimin dhe korrigjimin e programit.

Hierarkiaështë një sistem i renditur ose i renditur abstraksionesh. Parimi i hierarkisë nënkupton përdorimin e hierarkive në zhvillimin e sistemeve softuerike.

OOP përdor dy lloje hierarkie.

1. Hierarkia e tërë/pjesës- tregon se disa abstraksione përfshihen në abstraksionin e konsideruar, pasi pjesët e tij, për shembull, një llambë përbëhet nga një bazë, një filament inkandeshent dhe një llambë. Ky version i hierarkisë përdoret në procesin e ndarjes së sistemit në faza të ndryshme të projektimit (në nivelin logjik - kur zbërthehet zona e temës në objekte, në nivelin fizik - kur zbërthehet sistemi në module dhe kur ndahen proceset individuale në një sistemi me shumë procese).

2. Hierarkia e Përgjithshme / Specifike- tregon se një abstraksion është një rast i veçantë i një abstraksioni tjetër, për shembull, "një tavolinë ngrënieje është një lloj tavoline specifike", dhe "tavolinat janë një lloj specifik mobiljesh". Përdoret në zhvillimin e strukturës së klasave, kur klasat komplekse ndërtohen në bazë të atyre më të thjeshta duke u shtuar karakteristika të reja dhe, ndoshta, duke sqaruar ato ekzistuese.

Një nga mekanizmat më të rëndësishëm të OOP është trashëgimia e pronës në hierarkinë publike/private. Trashëgimia- kjo është një marrëdhënie e tillë midis abstraksioneve, kur njëri prej tyre përdor pjesën strukturore ose funksionale të një tjetri ose disa abstraksione të tjera (përkatësisht, trashëgimi e thjeshtë dhe e shumëfishtë).

Duke shtypur- ky është një kufizim i vendosur në vetitë e objekteve dhe parandalon këmbyeshmërinë e abstraksioneve të llojeve të ndryshme (ose ngushton shumë mundësinë e një zëvendësimi të tillë). Në gjuhët me shtypje të fortë, një lloj deklarohet për çdo objekt programi (ndryshore, nënprogram, parametër, etj.), i cili përcakton një grup operacionesh në objektin përkatës të programit. Gjuhët e programimit të bazuara në Pascal të diskutuara më poshtë përdorin shtypje strikte, ndërsa gjuhët e bazuara në C përdorin shtypje mesatare.

Përdorimi i parimit të shtypjes siguron:

1) zbulimi i hershëm i gabimeve që lidhen me operacionet e paligjshme në objektet softuerike (gabimet zbulohen në fazën e përpilimit të programit kur kontrolloni pranueshmërinë e kryerjes së këtij operacioni në një objekt softuerësh);

2) thjeshtësimi i dokumentacionit;

3) aftësia për të gjeneruar kod më efikas.

Lloji mund të lidhet me objektin e programit në mënyrë statike (lloji i objektit përcaktohet në kohën e përpilimit - lidhje e hershme) dhe në mënyrë dinamike (lloji i objektit përcaktohet vetëm gjatë ekzekutimit të programit - lidhje me vonesë). Zbatimi i lidhjes së vonë në një gjuhë programimi ju lejon të krijoni variabla - tregues për objektet që i përkasin klasave të ndryshme ( objekte polimorfike), gjë që zgjeron ndjeshëm aftësitë e gjuhës.

Paralelizmi- vetia e disa abstraksioneve të jenë në gjendje aktive në të njëjtën kohë, d.m.th. kryejnë disa operacione.

Ekzistojnë një numër detyrash, zgjidhja e të cilave kërkon ekzekutimin e njëkohshëm të disa sekuencave të veprimeve. Detyra të tilla, për shembull, përfshijnë detyra të kontrollit automatik të disa proceseve.

Paralelizmi real arrihet vetëm kur detyra të këtij lloji zbatohen në sistemet multiprocesorike, kur është e mundur të ekzekutohet çdo proces nga një procesor i veçantë. Sistemet me një procesor simulojnë paralelizmin duke ndarë kohën e procesorit midis detyrave për të kontrolluar procese të ndryshme. Në varësi të llojit të sistemit operativ të përdorur (i vetëm ose me shumë programe), ndarja e kohës mund të kryhet ose nga sistemi që po zhvillohet (si në MS DOS) ose nga sistemi operativ i përdorur (si në sistemet Windows).

Qëndrueshmëria- vetia e abstraksionit të ekzistojë në kohë, pavarësisht nga procesi që gjeneroi objektin e caktuar softuer, dhe/ose në hapësirë, duke lëvizur nga hapësira e adresave në të cilën është krijuar.

Të dallojë:

1) të përkohshme objekte që ruajnë rezultatet e ndërmjetme të disa veprimeve, për shembull, llogaritjet;

2) lokal objektet që ekzistojnë brenda nënprogrameve, jetëgjatësia e të cilave llogaritet nga thirrja e nënprogramit deri në përfundimin e saj;

3) globale objektet që ekzistojnë ndërsa programi është i ngarkuar në memorie;

4) të konservuara objekte, të dhënat e të cilave ruhen në skedarët e memories së jashtme ndërmjet sesioneve të programit.

Të gjitha parimet e mësipërme zbatohen në një shkallë ose në një tjetër në versione të ndryshme të gjuhëve të orientuara nga objekti.

Me vullnetin e fatit, më duhet të lexoj një kurs të veçantë për modelet e dizajnit në universitet. Kursi special është i detyrueshëm, prandaj studentët vijnë tek unë shumë ndryshe. Sigurisht, mes tyre ka edhe programues praktikantë. Por, për fat të keq, shumica e njerëzve kanë vështirësi edhe të kuptojnë termat bazë të OOP.

Për ta bërë këtë, u përpoqa të shpjegoj konceptet bazë të OOP (klasa, objekti, ndërfaqja, abstraksioni, kapsulimi, trashëgimia dhe polimorfizmi) duke përdorur pak a shumë shembuj të gjallë.

Pjesa e parë më poshtë ka të bëjë me klasat, objektet dhe ndërfaqet.
Pjesa e dytë ilustron kapsulimin, polimorfizmin dhe trashëgiminë

Konceptet bazë të OOP

Klasa
Imagjinoni se jeni duke projektuar një makinë. Ju e dini që një makinë duhet të përmbajë një motor, pezullim, dy fenerë, 4 rrota, etj. Ju gjithashtu e dini se makina juaj duhet të jetë në gjendje të marrë dhe të ngadalësojë, të kthehet dhe të kthehet prapa. Dhe, më e rëndësishmja, ju e dini saktësisht se si ndërveprojnë motori dhe rrotat, sipas çfarë ligjesh lëvizin boshti me gunga dhe boshti me gunga, si dhe se si janë rregulluar diferencialet. Ju jeni të sigurt në njohuritë tuaja dhe filloni të dizajnoni.

Ju përshkruani të gjitha pjesët që përbëjnë automjetin tuaj dhe se si këto pjesë ndërveprojnë me njëra-tjetrën. Përveç kësaj, ju përshkruani se çfarë duhet të bëjë përdoruesi për ta bërë makinën të frenojë ose të ndezë fenerët me rreze të gjatë. Rezultati i punës suaj do të jetë një skicë. Sapo keni zhvilluar atë që quan OOP Klasa.

KlasaËshtë një mënyrë e përshkrimit të një entiteti, përcaktimit të gjendjes dhe sjelljes në varësi të kësaj gjendjeje, si dhe rregullave për ndërveprimin me këtë subjekt (kontratë).

Nga pikëpamja e programimit, një klasë mund të shihet si një grup të dhënash (fusha, atribute, anëtarë të klasës) dhe funksione për të punuar me to (metoda).

Nga pikëpamja e strukturës së programit, një klasë është një lloj kompleks i të dhënave.

Në rastin tonë, klasa do të përfaqësojë entitetin - makinën. Atributet e klasës do të jenë motori, pezullimi, trupi, katër rrotat, etj. Metodat e klasës do të jenë "hapni derën", "shtypni pedalin e gazit", dhe gjithashtu "pomponi një pjesë të benzinës nga rezervuari i gazit në motor". Dy metodat e para janë të disponueshme për ekzekutim nga klasa të tjera (në veçanti, klasa "Driver"). Ky i fundit përshkruan ndërveprimet brenda klasës dhe nuk është i disponueshëm për përdoruesit.

Në të ardhmen, pavarësisht se fjala "përdorues" lidhet me Klondike Solitaire dhe Microsoft Word, ne do t'i referohemi si përdorues atyre programuesve që përdorin klasën tuaj, duke përfshirë edhe veten tuaj. Personi që është autori i klasës, ne do ta quajmë zhvilluesin.

Nje objekt
Ju keni bërë një punë të shkëlqyer dhe makinat e projektuara sipas vizatimeve tuaja po rrokullisen nga linja e montimit. Këtu janë ata, duke qëndruar në rreshta të barabartë në oborrin e fabrikës. Secila prej tyre përsërit saktësisht vizatimet tuaja. Të gjitha sistemet ndërveprojnë pikërisht ashtu siç keni projektuar. Por çdo makinë është unike. Të gjithë kanë një numër trupi dhe motori, por të gjithë këta numra janë të ndryshëm, makinat ndryshojnë në ngjyra dhe disa madje kanë kallëpe në vend të disqeve të stampuara. Këto makina janë në thelb objekte të klasës suaj.

Objekti (shembull)Është një anëtar i veçantë i një klase me një gjendje dhe sjellje specifike që përcaktohet plotësisht nga klasa.

Me fjalë të thjeshta, një objekt ka vlera specifike të atributeve dhe metoda që funksionojnë në këto vlera bazuar në rregullat e përcaktuara në klasë. Në këtë shembull, nëse një klasë është një makinë abstrakte nga "bota e ideve", atëherë objekti është një makinë specifike që qëndron nën dritaret tuaja.

Ndërfaqja
Kur shkojmë në një aparat kafeje ose hipim pas timonit, ne fillojmë të ndërveprojmë me ta. Zakonisht, ndërveprimi zhvillohet me ndihmën e një grupi të caktuar elementësh: një vend për pranimin e monedhave, një buton për zgjedhjen e një pije dhe një ndarje për shpërndarjen e një gote në një aparat kafeje; timoni, pedalet, leva e marsheve ne veture. Ekziston gjithmonë një grup i kufizuar kontrollesh me të cilat ne mund të ndërveprojmë.

NdërfaqjaËshtë një koleksion i metodave të klasës në dispozicion për përdorim nga klasa të tjera.

Natyrisht, ndërfaqja e një klase do të jetë një grup i të gjitha metodave të saj publike së bashku me një grup atributesh publike. Në thelb, një ndërfaqe specifikon një klasë, duke përcaktuar qartë të gjitha veprimet e mundshme në të.
Një shembull i mirë i një ndërfaqeje do të ishte pulti i makinës, i cili ju lejon të përdorni metoda të tilla si rritja e shpejtësisë, frenimi, rrotullimi, ndryshimi i marsheve, ndezja e fenerëve, etj. Kjo është, të gjitha veprimet që një klasë tjetër (në rastin tonë, shoferi) mund të kryejë kur ndërvepron me makinën.

Kur përshkruani një ndërfaqe klase, është shumë e rëndësishme të vendosni një ekuilibër midis fleksibilitetit dhe thjeshtësisë. Një klasë me një ndërfaqe të thjeshtë do të jetë e lehtë për t'u përdorur, por do të ketë probleme që nuk do të jetë në gjendje t'i zgjidhë me ndihmën e saj. Në të njëjtën kohë, nëse ndërfaqja është fleksibël, atëherë, ka shumë të ngjarë, ajo do të përbëhet nga metoda mjaft komplekse me një numër të madh parametrash që do t'ju lejojnë të bëni shumë, por përdorimi i tij do të jetë i mbushur me vështirësi të mëdha dhe rrezik të bërë një gabim, diçka konfuze.

Një shembull i një ndërfaqe të thjeshtë do të ishte një makinë me një transmetim automatik. Çdo bjonde që ka përfunduar një kurs dy-javor të vozitjes do të jetë në gjendje të zotërojë shumë shpejt menaxhimin e tij. Nga ana tjetër, duhen disa muaj apo edhe vite trajnim të vështirë për të zotëruar kontrollin e një avioni modern pasagjerësh. Nuk do të doja të isha në bordin e një Boeing të drejtuar nga një burrë me dy javë përvojë fluturimi. Nga ana tjetër, ju kurrë nuk do ta detyroni një makinë të ngrihet dhe të fluturojë nga Moska në Uashington.

Të gjitha gjuhët e orientuara nga objekti përdorin tre parime themelore të programimit të orientuar nga objekti:

  • Kapsulimi... Si i fsheh kjo gjuhë tiparet e brendshme të zbatimit të një objekti?
  • Trashëgimia... Si e ofron kjo gjuhë aftësinë për të ripërdorur kodin e programit?
  • Polimorfizmi... Si ju lejon kjo gjuhë të interpretoni objektet e lidhura në një mënyrë uniforme?

Parimi i parë i OOP është kapsulimi. Kapsulimi Është një mekanizëm programimi që lidh kodin dhe të dhënat që ai manipulon, i mbron ato nga aksesi dhe keqpërdorimi i jashtëm dhe fsheh detajet e zbatimit me anë të gjuhës. Për shembull, supozoni se po përdorim një klasë që përfaqëson objekte të llojit Pen. Një klasë e tillë përmbledh aftësinë e brendshme të objekteve për të vizatuar pika, vija dhe forma me trashësi dhe ngjyra të ndryshme. Parimi i kapsulimit ju lejon të thjeshtoni detyrën e programimit në kuptimin që nuk keni më nevojë të shqetësoheni për linjat e shumta të kodit që kryejnë punën e klasës nib prapa skenave. Gjithçka që kërkohet është të instantohet klasa nib dhe të ndërveprohet me të duke thirrur funksionet e saj.

Mbrojtja e të dhënave është një aspekt i rëndësishëm i kapsulimit. Në mënyrë ideale, të dhënat që karakterizojnë gjendjen e një objekti duhet të përkufizohen si private dhe të paarritshme për mjedisin e jashtëm. Në këtë rast, mjedisi i jashtëm i objektit do të detyrohet të kërkojë të drejtën për të ndryshuar ose lexuar vlerat përkatëse. Kështu, koncepti i kapsulimit pasqyron rregullin e përgjithshëm që fushat e të dhënave të një objekti nuk duhet të jenë të aksesueshme drejtpërdrejt nga një ndërfaqe publike. Nëse përdoruesi duhet të ndryshojë gjendjen e objektit, atëherë ai duhet ta bëjë atë jo drejtpërdrejt, por indirekt, duke përdorur funksionet e leximit ( marr()) dhe modifikimet ( vendosur()). Në C #, aksesueshmëria e të dhënave zbatohet në nivelin e sintaksës duke përdorur fjalë kyçe publike, private, të mbrojtura, dhe të brendshme të mbrojtura.

Brenda një objekti, kodi, të dhënat ose kodi dhe të dhënat mund të jenë private për objektet e tjera ose publike. Kodi dhe të dhënat private janë të njohura dhe të aksesueshme vetëm nga një pjesë tjetër e këtij objekti (d.m.th. vetëm nga vetë objekti). Prandaj, kodi dhe të dhënat private nuk mund të aksesohen nga ajo pjesë e programit që ekziston jashtë objektit të caktuar.

Parimi tjetër OOP është trashëgimisë , që nënkupton aftësinë e gjuhës për të ofruar ndërtimin e përkufizimeve të klasave të reja bazuar në përkufizimet e klasave ekzistuese. Në thelb, trashëgimia ju lejon të zgjeroni sjelljen e klasës bazë (e quajtur gjithashtu klasën e prindërve) duke ndërtuar një nënklasë (e quajtur derivatore ose klasë për fëmijë) që trashëgon karakteristikat dhe funksionalitetin e klasës mëmë. Në thelb, kjo formë e trashëgimisë është ripërdorimi i kodit të programit të një klase (bazë) në klasa të tjera (të rrjedhura prej saj). Në mënyrë tipike, në këtë rast, klasa fëmijë zgjeron aftësitë e klasës bazë duke shtuar disa aftësi të reja që nuk janë të disponueshme në klasën bazë. Kjo formë trashëgimie quhet "is-a" (domethënë të jetë e njëjtë, por me më shumë aftësi).


Një formë tjetër e ripërdorimit të kodit është modeli i lokalizimit / delegimit (i njohur gjithashtu si marrëdhënia ka-një lokalizim). Kjo formë nuk përdoret për të krijuar marrëdhënie klasë-nënklasë. Në vend të kësaj, një klasë mund të përcaktojë në përbërjen e saj disa ndryshore të një klase tjetër dhe të ekspozojë një pjesë ose të gjithë funksionalitetin e saj në mjedisin e jashtëm. Në këtë rast, klasa është më shumë si një kontejner që përmban shembuj të klasave të tjera.

Parimi i tretë i OOP është polimorfizëm ... Ai karakterizon aftësinë e një gjuhe për të interpretuar objektet e lidhura në të njëjtën mënyrë. Kjo veçori e gjuhës së orientuar nga objekti lejon klasën bazë të përcaktojë anëtarë të shumtë për të gjitha klasat e derivuara. Formalisht, ky anëtar i përbashkët quhet ndërfaqe polimorfike. Një ndërfaqe polimorfike për një klasë është ndërtuar duke përcaktuar një numër arbitrar Virtual dhe abstrakte funksione. Funksioni i klasës virtuale mund ndryshimi në klasën e prejardhur dhe funksioni abstrakt mund të jetë vetëm anashkaloj. Kur klasat e derivuara anashkalojnë funksionet e përcaktuara në klasën bazë, ato në thelb anashkalojnë përgjigjen e tyre ndaj kërkesës përkatëse. Përveç aftësisë për të anashkaluar funksionet, C # ofron mundësinë për të përdorur një formë tjetër të polimorfizmit - mbingarkimin e funksionit. Mbingarkimi duhet parë si një mundësi shtesë për të dalluar funksionet me të njëjtin emër, të ndryshëm në numrin ose llojin e argumenteve. Prandaj, mbingarkesa mund të aplikohet jo vetëm për funksionet - anëtarë të një klase, por edhe për funksionet globale.

Nuk mund të programoj në gjuhë të orientuara nga objekti. Nuk mësoi. Pas 5 vitesh programimi industrial Java, ende nuk di si të krijoj një sistem të mirë të orientuar nga objekti. 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ë hutojnë.

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

Seriozisht. E kam të vështirë të formuloj idetë kryesore të OOP. Në programimin funksional, një nga idetë kryesore është pashtetësia. Strukturisht, është dekompozim. Në ndarjen modulare, funksionale 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. Për OOP, unë nuk i di rregulla të tilla.
  • Abstraksioni
  • Kapsulimi
  • Trashëgimia
  • Polimorfizmi
Tingëllon si një grup rregullash, apo jo? Pra, kjo është ajo, rregullat që duhen ndjekur 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ë ne të afroheshim ndonjëherë me nivelin aktual të programeve nëse nuk do të ishim të armatosur me një mjet të tillë. Sidoqoftë, si krahasohet abstraksioni me OOP?

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

Së dyti, ka pasur gjithmonë abstraksione në programim, duke filluar me shënimet e Ada Lovelace, e cila konsiderohet të jetë programuesja e parë në histori. Që atëherë, njerëzit kanë krijuar vazhdimisht abstraksione në programet e tyre, shpesh duke pasur vetëm mjetet më të thjeshta për këtë. Pra, Abelson dhe Sussman, në librin e tyre të njohur, përshkruajnë se si të krijoni një sistem për zgjidhjen e ekuacioneve me mbështetjen e numrave kompleksë dhe madje edhe polinomeve, duke u armatosur vetëm me procedura dhe lista të lidhura. Pra, çfarë mjetesh shtesë të abstraksionit vjen me OOP? Unë nuk kam asnjë ide. Po theksoni kodin në nënprograme? Çdo gjuhë e nivelit të lartë mund ta bëjë këtë. Kombinimi i nënprogrameve në një vend? Ka mjaft module për këtë. Po shkruani? Ishte shumë kohë përpara PLO. Një shembull me një sistem për zgjidhjen e ekuacioneve tregon mirë se ndërtimi i niveleve të abstraksionit varet jo aq nga mjetet e gjuhës, sa nga aftësitë e programuesit.

Kapsulimi

Karta kryesore e kapsulimit është fshehja e zbatimit. Kodi i klientit sheh vetëm ndërfaqen dhe mund të mbështetet vetëm në të. Kjo liron duart e zhvilluesve që mund të vendosin të ndryshojnë zbatimin. Dhe kjo është vërtet e lezetshme. Por përsëri, pyetja është, çfarë ka të bëjë OOP me të? Gjithçka paradigmat e mësipërme nënkuptojnë fshehjen e zbatimit. Kur programoni në C, ju ndani një ndërfaqe në skedarët e kokës, Oberon ju lejon të bëni fushat dhe metodat lokale për modulin dhe së fundi, në shumë gjuhë, abstraksioni 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 - marrës dhe vendosës në Java, vetitë në C #, etj. (Në komente, zbuluam se disa objekte në gjuhët e programimit nuk janë objekte nga pikëpamja e OOP: objektet e transferimit të të dhënave janë vetëm përgjegjëse 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 , ato nuk kanë nevojë të kapsulohen. , metodat e aksesorëve ruhen më së miri për të mbajtur fleksibile arkitekturën. Ja sa e ndërlikuar është.) Për më tepër, disa gjuhë të orientuara nga objekti, si Python, nuk përpiqen të fshehin asgjë. por mbështetuni vetëm në mençurinë e zhvilluesve që përdorin këtë kod.

Trashëgimia

Trashëgimia është një nga gjërat e pakta të reja që ka dalë vërtet në skenë falë OOP. Jo, gjuhët e orientuara nga objekti nuk kanë krijuar një ide të re - trashëgimia mund të zbatohet lehtësisht 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 i përshtatet një klase, mund të krijoni një pasardhës dhe të anashkaloni disa nga funksionalitetet e tij. Në gjuhët që mbështesin trashëgiminë e shumëfishtë, si C ++ ose Scala (në këtë të fundit, në kurriz të 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 kopjimi i kodit.

Pra, kjo është ajo - çfarë e veçon OOP si një paradigmë nga të tjerët? Hmm ... nëse po, pse e përdorim kaq rrallë në kodin real? E mbani mend kur fola 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. Ithtarët 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 është shumë më pak e zakonshme. 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ë jo e nevojshme.

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 e sotme popullore çon në dizajn të brishtë. Pasi ka trashëguar nga një paraardhës, një klasë nuk mund të trashëgojë më nga të tjerët. Ndryshimi i paraardhësit bëhet gjithashtu i rrezikshëm. Sigurisht, ka modifikues privatë/të mbrojtur, por ata gjithashtu kërkojnë aftësi të forta psikike për të marrë me mend se si mund të ndryshojë një klasë dhe si mund ta përdorë kodi i klientit. Trashëgimia është aq e rrezikshme dhe e papërshtatshme sa kornizat e mëdha (siç janë Spring dhe EJB në Java) po i braktisin ato, duke kaluar në mjete të tjera jo të orientuara nga objekti (siç është metaprogramimi). Pasojat janë aq të paparashikueshme sa disa biblioteka (si p.sh. Guava) përshkruajnë modifikues për 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ë në lidhje me programimin e orientuar nga objekti. Falë polimorfizmit, një objekt i tipit Person duket si "Shandorkin Adam Impolitovich" në dalje dhe një objekt i llojit Point duket si "". Është ai 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 apo një varg në memorie. Kudo që ka ndërfaqe, polimorfizmi nënkuptohet.

Më pëlqen shumë polimorfizmi. Kështu që 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 për tip dhe se si mund të bëhet kjo. Shumicën e kohës funksionon siç duhet, gjë që është mjaft e mirë. Pyetja është: a është polimorfizmi vetë parimi që e dallon OOP nga paradigmat e tjera? Nëse do të më pyesnit mua (dhe duke qenë se po e lexoni këtë tekst, atëherë mund të supozoni se keni pyetur), unë do të përgjigjesha "jo". Dhe arsyeja është 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 mund t'i quaj polimorfike. Gjuhët me mbështetje polimorfizmi - po, kjo është në rregull. Por jo gjuhë polimorfike.

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

Pra, abstraksioni, kapsulimi, trashëgimia dhe polimorfizmi janë të gjitha në OOP, por asnjëra prej tyre nuk është e natyrshme në të. Atëherë çfarë është OOP? Besohet se thelbi i programimit të orientuar nga objekti qëndron në, në fakt, në objektet (tingëllon mjaft logjike) dhe klasa. Është ideja e kombinimit të kodit dhe të dhënave, si dhe ideja që objektet në program pasqyrojnë entitetet e botës reale. Ne do t'i rikthehemi këtij mendimi më vonë, por fillimisht do të vendosim disa i.

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

Nga seksioni i mëparshëm, mund të shihni se gjuhët e programimit mund të jenë shumë të ndryshme 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ë me shumë mundësi nuk do të gjeni fare 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, pasi ju mund të shkruani lehtësisht 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ë thirrjeve të metodës, objektet i dërgonin mesazhe njëri-tjetrit dhe nëse marrësi nuk mund të përpunonte atë që erdhi, ai thjesht ia përcillte mesazhin dikujt tjetër.

Lisp e zakonshme. CL fillimisht ndoqi të njëjtën paradigmë. Më pas, zhvilluesit vendosën që do të duhej shumë kohë për të shkruar `(send obj” some-message) `, dhe e konvertuan shënimin në një thirrje metode -` (disa-metod obj) `. Sot Common Lisp ka një sistem të zhvilluar të objektit Programimi i orientuar (CLOS) me mbështetje për trashëgimi të shumëfishtë, multimetoda dhe metaklasa. Karakteristika dalluese është se OOP në CL nuk rrotullohet rreth objekteve, por rreth funksioneve të përgjithshme.

Clojure. Clojure ka deri në 2 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 të trashëguara nga gjuha S (gjë që nuk është për t'u habitur, duke qenë se R është një zbatim me burim të hapur i S-së komerciale). S4 kryesisht korrespondon me implementimet OOP në gjuhët moderne të zakonshme. S3 është një version me peshë më të lehtë, i zbatuar në mënyrë elementare me anë të vetë gjuhës: krijohet një funksion i përbashkët që dërgon kërkesat nga atributi "class" i 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 një klasë string duket shumë bukur).

Python. Në përgjithësi, ai i përmbahet të njëjtit koncept si gjuhët kryesore, por gjithashtu mbështet kalimin e një kërkimi të atributeve te 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: llojet e të dhënave (llojet) 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 të 2 objekteve), dhe të gjithë numrat janë gjithashtu në klasat Num (veprimet mbi numrat) dhe Ord (operacionet<, <=, >=,>). Në gjuhët kryesore, klasat (të dhënat) korrespondojnë me llojet dhe ndërfaqet me klasat e tipit.

Shtet apo pa shtetësi?

Por përsëri te sistemet më të zakonshme të programimit të orientuar nga objekti. Ajo që nuk kam mundur kurrë të kuptoj ë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, shumë). Pastaj erdhën objektet, dhe gjithashtu nuk ishte asgjë (megjithëse u bë shumë më e vështirë të lexosh programet - qeni im po ecte [kë?], Dhe llogaria po tërhiqte para [nga ku?]). Pastaj mësova për fshehjen e të dhënave. Unë ende mund të shëtisja qenin, por nuk mund ta shihja përbërjen e ushqimit të tij. Ushqimi nuk ka kryer asnjë veprim (ju ndoshta mund të shkruani se çfarë ushqimi është për të ngrënë (qeni), por unë ende preferoj që qeni im të hajë ushqimin sesa anasjelltas). Ushqimi është vetëm të dhëna, dhe unë (dhe qeni im) thjesht duhej t'i qasja. Gjithçka thjesht... Por nuk ishte më e mundur të futej në kornizën e paradigmës, si në xhinset e vjetra të fundit të viteve '90.

Në rregull, ne kemi metoda të aksesit të të dhënave. Le të shkojmë në 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 (betohem se ishte e rrethuar nga shkëlqimi dhe mbi shkronjat t dhe l kishte një aureolë). Një studim i shkurtër i literaturës hapi një botë të mrekullueshme të rrjedhës së kontrollit transparent dhe multithreading të thjeshtë pa pasur nevojë të mbani gjurmët e konsistencës së objektit. Sigurisht, menjëherë doja të prekja këtë botë të mrekullueshme. Sidoqoftë, kjo nënkuptonte një braktisje të plotë të çdo rregulli - tani nuk ishte e qartë nëse qeni duhet të ecte vetë, apo për këtë duhej një WalkManager i veçantë; A keni nevojë për një llogari, ose Banka do të trajtojë të gjitha punët, dhe nëse po, atëherë duhet të heqë paratë në mënyrë statike ose dinamike, etj. Numri i rasteve të përdorimit është rritur në mënyrë eksponenciale dhe të gjitha opsionet në të ardhmen mund të çojnë në nevojën për rifaktorim serioz.

Unë ende nuk e di se kur një objekt duhet të bëhet pa shtet, kur është i gjendjes dhe kur vetëm një kontejner të dhënash. Ndonjëherë kjo është e qartë, por më shpesh nuk është.

Shtypja: statike apo dinamike?

Një gjë tjetër që nuk mund ta kuptoj fare për gjuhët si C # dhe Java është nëse ato janë të shtypura në mënyrë statike apo dinamike. Ndoshta shumica e njerëzve do të thërrasin: “Çfarë marrëzie! Natyrisht, 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ë programuesi, duke shkruar tipin X në parametrat e metodës, mund të jetë i sigurt se objektet e tipit X do t'i kalojnë gjithmonë atij? Kjo është e drejtë - nuk mundet, sepse metodës X mund t'i jepet një parametër i tipit X ose trashëgimtari i tij... Do të duket, pra çfarë? Trashëgimtarët e klasës X do të kenë ende të njëjtat metoda si X. Metodat sipas metodave, por logjika e punës mund të jetë krejtësisht e ndryshme. Rasti më i zakonshëm është kur klasa e fëmijës 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ë kaloni disa javë për të analizuar arkitekturën dhe algoritmet e bibliotekës, ose thjesht do të thërrisni rastësisht metoda me një nënshkrim të përshtatshëm). Si rezultat, programi funksionon, por shpejtësia e punës 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ësi i 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ë null, i cili 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 prej tyre. null nuk ka fusha ose 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) do të detyrohet të përdorë lloje të veçanta (Ndoshta në Haskell, Option në Scala) për të mbështjellë funksione që mund të kthejnë nule në gjuhë të tjera. Si rezultat, njerëzit shpesh thonë për Haskell "është e vështirë të përpilosh një program në të, por nëse funksionoi, atëherë ka shumë të ngjarë që funksionon siç duhet".

Nga ana tjetër, gjuhët e zakonshme nuk janë padyshim të shtypura në mënyrë dinamike, që do të thotë se ato nuk kanë karakteristika të tilla si thjeshtësia e ndërfaqeve dhe fleksibiliteti i procedurave. Si rezultat, të shkruarit në stilin Python ose Lisp gjithashtu bëhet i pamundur.

Cili është ndryshimi se si quhet ky shtypje nëse dihen gjithsesi të gjitha rregullat? Dallimi është se në cilën anë t'i qasemi dizajnit arkitektonik. Ekziston një debat i gjatë se si të ndërtohet një sistem: a bëjnë shumë lloje dhe pak funksione, apo pak lloje dhe shumë funksione? Qasja e parë përdoret gjerësisht 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 veta (në fund, mos harroni se Java dhe C # janë platforma shumëgjuhëshe), por sa herë që nis një projekt të ri mendoj se ku të filloj dizajnimin - me lloje ose nga funksionale.

Dhe më tej...

Nuk di si ta modeloj problemin. Besohet se OOP ju lejon të shfaqni objekte të botës reale në program. Megjithatë, 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 pushim dreke), dhe programi përfshin VygulManager, AccountFabrika ... mirë, e kuptoni idenë . Dhe 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 heq kënaqësinë e shëtitjes së qenit, dhe unë i marr paratë nga llogaria bankare e pashpirt (hej, ku është ajo vajza e ëmbël për të cilën ndërrova para javën e kaluar?).

Ndoshta jam snob, por ndihesha shumë më mirë kur të dhënat në kompjuter ishin vetëm të dhëna, edhe nëse përshkruanin qenin tim ose llogarinë bankare. Me të dhënat, mund të bëja gjithçka që ishte e përshtatshme, pa shikuar botën reale.

Unë gjithashtu nuk e di se si ta zbërthej siç duhet funksionalitetin. Në Python ose C ++, nëse më nevojitej 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 #, duhet ta zhvendos në një klasë të veçantë StringUtils. Në gjuhët jo-OO, mund të deklaroja një mbështjellës ad hoc për të kthyer dy vlera nga një funksion (shumën e tërhequr dhe gjendjen e llogarisë). Në gjuhët OOP, më duhet të krijoj një klasë të plotë ResultTransaction. Dhe për një person të ri në projekt (ose edhe për veten time brenda një jave), kjo klasë do të duket saktësisht e njëjtë e rëndësishme dhe themelore në arkitekturën e sistemit. 150 skedarë, të gjithë po aq të rëndësishëm dhe themelorë - oh po, arkitekturë transparente, nivele të shkëlqyera abstraksioni.

Nuk mund 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ë llojit URL, më pas një objekt të tipit HttpConnection, më pas një objekt të llojit Kërkesë ... mirë, e kuptoni idenë. Në programimin procedural, unë thjesht do të quaj disa procedura, duke u kaluar atyre strukturën e 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 që mund të krijojë një program vërtet të bukur në një gjuhë të orientuar drejt objektit. Epo, unë vetëm mund t'i kem zili.

Artikujt kryesorë të lidhur