Kako podesiti pametne telefone i računare. Informativni portal
  • Dom
  • Windows 8
  • Informatičke laboratorije, ispit. Principi objektno orijentiranog programiranja

Informatičke laboratorije, ispit. Principi objektno orijentiranog programiranja

(kako OOP znači) je, prije svega, programska paradigma.
Paradigma programiranja definira kako programer vidi izvršenje programa.
Tako je za OOP paradigmu karakteristično da programer program posmatra kao skup objekata koji su u interakciji, dok se, na primjer, u funkcionalnom programiranju program predstavlja kao niz proračuna funkcija. Proceduralno programiranje ili, kako se još pravilno naziva, klasično operativno, podrazumijeva pisanje algoritma za rješavanje problema; međutim, očekivana svojstva konačnog rezultata nisu opisana niti naznačena. Strukturirano programiranje se u osnovi pridržava istih principa kao i proceduralno programiranje, samo ih malo dopunjujući korisnim trikovima.
Paradigme neproceduralnog programiranja, koje uključuju objektno orijentisanu paradigmu, imaju potpuno različite ideje.
Definicija Gradi Bucha je: “ Objektno orijentirano programiranje To je metodologija programiranja koja se zasniva na predstavljanju programa kao skupa objekata, od kojih je svaki implementacija određene klase (tip posebne vrste), a klase formiraju hijerarhiju zasnovanu na principima nasljeđivanja”.
Strukturno i objektno orijentirano programiranje zasniva se na naučnoj metodi kao što je raspadanje- metoda koja koristi strukturu problema i omogućava vam da podijelite rješenje zajedničkog velikog problema na rješavanje niza manjih problema. OOP dekompozicija se ne dešava prema algoritmima, već prema objektima koji se koriste za rješavanje problema. Ova dekompozicija smanjuje veličinu softverskih sistema ponovnim korištenjem uobičajenih mehanizama. Poznato je da su sistemi vizuelnog programiranja ili sistemi zasnovani na principima objektno orijentisanog programiranja fleksibilniji i lakše se razvijaju tokom vremena.

Istorija razvoja OOP-a datira iz kasnih 60-ih godina. Prvi objektno orijentisani jezik bio je programski jezik Simula, kreiran u kompjuterskom centru u Norveškoj. Jezik je bio namijenjen da simulira situacije u stvarnom svijetu. Karakteristika Simule je bila da je program napisan na jeziku organizovan programskim objektima. Objekti su imali instrukcije zvane metode i podatke zvane varijable; metode i podaci određivali su ponašanje objekta. Tokom procesa modeliranja, objekat se ponašao u skladu sa svojim standardnim ponašanjem i, ako je potrebno, menjao je podatke kako bi odražavao uticaj dodeljene akcije.

Ima ih dovoljno objektno orijentisani programski jezici, od kojih su trenutno najpopularniji C++, Delphi, Java, Visual Basic, Flash. Ali, pored toga, mnogi jezici koji se obično smatraju proceduralnim paradigmom takođe imaju OOP svojstva, budući da su u stanju da rade sa objektima. Dakle, objektno orijentirano programiranje u C-u je veliki dio programiranja na ovom jeziku, isto vrijedi i za OOP u Python-u i mnogim drugim strukturiranim jezicima.

Kada govorimo o OOP-u, često se pojavljuje druga definicija - vizuelno programiranje... Dodatno pruža široku upotrebu prototipova objekata, koji su definirani kao klase objekata.
Događaji. U mnogim okruženjima vizualnog programiranja implementirana je karakteristika (pored enkapsulacije, polimorfizma i nasljeđivanja) objekta - događaj. Događaji u objektno orijentiranom programiranju su sposobnost obrade takozvanih poruka (ili događaja) primljenih od Windows operativnog sistema ili samog programa. Ovaj princip je tipičan za sve komponente okruženja koje obrađuju različite događaje koji se javljaju tokom izvršavanja programa. U stvari, događaj je neka vrsta akcije koja aktivira standardnu ​​reakciju objekta. Događaj se može smatrati, na primjer, klikom na dugme miša, pomeranjem kursora miša preko stavke menija, otvaranjem kartice itd. Redoslijed izvršavanja određenih radnji određen je upravo događajima koji se dešavaju u sistemu i reakcijom objekata na njih.
Klase i objekti u OOP-u- različiti koncepti. Koncept klase u OOP-u je tip podataka (isto kao, na primjer, Real ili String), a objekt je specifična instanca klase (njena kopija), pohranjena u memoriji računala kao varijabla odgovarajućeg tipa .
Klasa je strukturirani tip podataka. Klasa uključuje opis polja podataka, kao i procedure i funkcije koje rade sa tim poljima podataka. OOP metoda- to su takve procedure i funkcije u odnosu na klase.
Klase imaju polja (poput tipa podataka zapisa), svojstva koja su slična poljima, ali imaju dodatne deskriptore koji definišu mehanizme za pisanje i čitanje podataka i metode – potprograme koji imaju za cilj promenu polja i svojstva klase.

Osnovni principi OOP-a

Pored rukovanja događajima, principi objektno orijentisanog programiranja su enkapsulacija, nasljeđivanje, podklasiranje i polimorfizam. Oni su posebno korisni i neophodni kada se razvijaju aplikacije koje se mogu replicirati i koje se lako održavaju.
Objekt kombinuje metode i svojstva koja ne mogu postojati odvojeno od njega. Stoga, ako se objekt izbriše, tada se brišu njegova svojstva i pridružene metode. Prilikom kopiranja dešava se ista stvar: objekt se kopira kao cjelina. OOP inkapsulacija- ovo je opisana karakteristika.

OOP princip nasljeđivanja i podklase

Apsolutno svi objekti su kreirani na osnovu klasa, dok oni nasljeđuju svojstva i metode ovih klasa. Zauzvrat, klase se mogu kreirati na osnovu drugih klasa (roditelja), tada se takve klase nazivaju podklase (potomci). Potklase nasljeđuju sva svojstva i metode roditeljske klase. Osim toga, za podklasu ili klasu potomka, možete definirati nova, vlastita svojstva i metode, kao i promijeniti metode roditeljske klase. Promjene svojstava i metoda roditeljske klase se prate u podklasama zasnovanim na ovoj klasi, kao iu objektima kreiranim od podklasa. Ovo je OOP nasljeđivanje.

OOP polimorfizam

U objektno orijentiranom programiranju, polimorfizam se karakterizira kao zamjenjivost objekata sa istim interfejsom. Ovo se može objasniti na sljedeći način: klasa potomak nasljeđuje instance metoda roditeljske klase, ali se izvršavanje ovih metoda može dogoditi na drugačiji način, što odgovara specifičnostima klase potomaka, odnosno modificirano.
To jest, ako u proceduralnom programiranju ime procedure ili funkcije jedinstveno identifikuje izvršni kod povezan sa datom procedurom ili funkcijom, tada u objektno orijentiranom programiranju možete koristiti ista imena metoda za izvođenje različitih radnji. Odnosno, rezultat izvršavanja iste metode zavisi od tipa objekta na koji je ova metoda primenjena.

Stranica predstavlja djelomičnu teoriju objektno orijentiranog programiranja za početnike i OOP primjere rješavanja problema. Lekcije OOP stranice su detaljni algoritmi za zadatak. Na osnovu izvođenja ovih laboratorijskih radova student će u budućnosti moći samostalno rješavati druge slične probleme.
Želimo vam lako i zabavno učenje o objektno orijentiranom programiranju!

Prepoznatljive karakteristike OOP-a

1) OO pristup se fokusira na podatke kao najstabilnije elemente računarskog sistema

2) OO pristup vam omogućava da razvijete programski kod koji ima za cilj ponavljajuću upotrebu

3) OO pristup omogućava bolju skalabilnost u softverskim projektima, tj. stvaranje programa različitog stepena složenosti, stoga većina modernih tehnologija dizajna uključuje upotrebu OOP-a.

U teoriji OO programiranja pristup se definira kao tehnologija za kreiranje složenog softvera, kat. Zasnovano na predstavljanju programa kao zbirke softverskih objekata. Glavna prednost OOP-a je smanjenje broja međumodulskih poziva i smanjenje količine informacija koje se prenose između modula, u poređenju sa modularnim programiranjem. To se postiže potpunijom lokalizacijom podataka i njihovom integracijom sa rutinama obrade, što omogućava gotovo samostalan razvoj pojedinih dijelova (objekata) programa.

Osim toga, objektni pristup nudi nove alate za tehnološki razvoj, kao što su nasljeđivanje, polimorfizam, kompozicija, popunjavanje, omogućavajući vam da konstruišete složenije objekte od jednostavnijih. Rezultat je značajno povećanje ponovne upotrebe koda, mogućnost kreiranja biblioteka objekata za različite aplikacije i dodatne mogućnosti za programere da kreiraju sisteme povećane složenosti.

OOP se zasniva na sljedećem principi:

1) apstrakcija;

2) ograničenje pristupa;

3) modularnost;

4) hijerarhija;

5) kucanje;

6) paralelizam;

7) održivost.

Hajde da razjasnimo šta je svaki princip.

Apstrakcija- proces isticanja apstrakcija u domenu problema. Apstrakcija je skup bitnih karakteristika objekta koje ga razlikuju od svih drugih vrsta objekata i na taj način jasno definišu karakteristike ovog objekta sa stanovišta daljeg razmatranja i analize. U skladu sa definicijom, primenjena apstrakcija stvarnog objekta u suštini zavisi od problema koji se rešava: u jednom slučaju će nas zanimati oblik objekta, u drugom težina, u trećem - materijali od kojih je predmet je napravljen, u četvrtom - zakon kretanja predmeta itd. Savremeni nivo apstrakcije pretpostavlja objedinjavanje svih svojstava apstrakcije (kako koja se tiču ​​stanja analiziranog objekta, tako i određivanja njegovog ponašanja) u jednu programsku jedinicu, određenu apstraktnog tipa(Razred).

Ograničenje pristupa(Enkapsulacija je princip da se svaka klasa treba smatrati crnom kutijom - korisnik klase treba da vidi i koristi samo dio interfejsa klase (tj. listu deklariranih svojstava i metoda klase) i ne ulazi u njega. Prema tome, podaci se obično inkapsuliraju u klasu na način da se pristup njima radi čitanja ili pisanja ne vrši direktno, već uz pomoć metoda. Princip enkapsulacije (teoretski) omogućava da se minimizirati broj veza između klasa i, shodno tome, pojednostaviti samostalnu implementaciju i modifikaciju klasa.) Ovo je skrivanje pojedinačnih elemenata apstrakcije implementacije koje ne utiče na njene bitne karakteristike u celini.


Potreba za ograničenjem pristupa podrazumijeva razliku između dva dijela u opisu apstrakcije:

a) interfejs- skup eksterno dostupnih elemenata implementacije apstrakcije (glavne karakteristike stanja i ponašanja);

b) realizacija- skup elemenata nedostupnih spolja za implementaciju apstrakcije (unutrašnja organizacija apstrakcije i mehanizmi za implementaciju njenog ponašanja).

Ograničavanje pristupa u OOP-u omogućava programeru da:

1) sprovodi izgradnju sistema u fazama, ne ometajući se karakteristikama implementacije korišćenih apstrakcija;

2) lako je modifikovati implementaciju pojedinačnih objekata, što u pravilno organizovanom sistemu ne zahteva promene na drugim objektima.

Kombinacija kombinovanja svih svojstava objekta (koji čine njegovo stanje i ponašanje) u jednu apstrakciju i ograničavanja pristupa implementaciji ovih svojstava naziva se inkapsulacije .

Modularnost- ovo je princip razvoja softverskog sistema koji podrazumijeva njegovu implementaciju u obliku zasebnih dijelova (modula). Prilikom dekompozicije sistema na module, poželjno je kombinovati logički povezane dijelove, osiguravajući što je moguće više smanjenje broja eksternih veza između modula. Princip je naslijeđen iz modularnog programiranja, slijedeći ga, pojednostavljuje dizajn i otklanjanje grešaka u programu.

Hijerarhija je rangirani ili uređeni sistem apstrakcija. Princip hijerarhije podrazumeva korišćenje hijerarhije u razvoju softverskih sistema.

OOP koristi dvije vrste hijerarhije.

1. Cijeli / dio hijerarhije- pokazuje da su neke apstrakcije uključene u razmatranu apstrakciju, jer se njeni dijelovi, na primjer, lampa sastoji od postolja, žarulje sa žarnom niti i žarulje. Ova verzija hijerarhije se koristi u procesu podjele sistema u različitim fazama projektovanja (na logičkom nivou - kada se predmetna oblast dekomponuje na objekte, na fizičkom nivou - kada se sistem dekomponuje na module i kada se pojedinačni procesi odvajaju u višeprocesni sistem).

2. Opća/specifična hijerarhija- pokazuje da je neka apstrakcija poseban slučaj druge apstrakcije, na primjer, "trpezarijski sto je posebna vrsta stola", a "stolovi su posebna vrsta namještaja". Koristi se u razvoju strukture klasa, kada se složene klase grade na osnovu jednostavnijih dodavanjem novih karakteristika i, eventualno, razjašnjavanjem postojećih.

Jedan od najvažnijih mehanizama OOP-a je nasljeđivanje imovine u javnoj/privatnoj hijerarhiji. Nasljedstvo- to je takav odnos između apstrakcija, kada jedna od njih koristi strukturni ili funkcionalni dio druge ili nekoliko drugih apstrakcija (odnosno, jednostavno i višestruko nasljeđivanje).

Tipkanje- ovo je ograničenje nametnuto svojstvima objekata i onemogućava zamjenjivost apstrakcija različitih tipova (ili uvelike sužava mogućnost takve zamjene). U jako tipiziranim jezicima, tip je deklariran za svaki programski objekt (varijabla, potprogram, parametar, itd.), koji definira skup operacija na odgovarajućem programskom objektu. Programski jezici zasnovani na Pascalu o kojima se govori u nastavku koriste strogo kucanje, dok jezici zasnovani na C koriste srednje kucanje.

Korišćenje principa kucanja obezbeđuje:

1) rano otkrivanje grešaka povezanih sa nedozvoljenim operacijama na softverskim objektima (greške se otkrivaju u fazi kompilacije programa prilikom provere prihvatljivosti izvođenja ove operacije na softverskom objektu);

2) pojednostavljenje dokumentacije;

3) sposobnost generisanja efikasnijeg koda.

Tip se može statički vezati za programski objekt (tip objekta se određuje u vrijeme kompajliranja - rano vezivanje) i dinamički (tip objekta se određuje samo tokom izvršavanja programa - kasno uvezivanje). Implementacija kasnog povezivanja u programskom jeziku omogućava vam da kreirate varijable - pokazivače na objekte koji pripadaju različitim klasama ( polimorfni objekti), što značajno proširuje mogućnosti jezika.

Paralelizam- svojstvo više apstrakcija da istovremeno budu u aktivnom stanju, tj. izvršiti neke operacije.

Postoji niz zadataka, za čije rješavanje je potrebno istovremeno izvršavanje nekoliko nizova radnji. Takvi zadaci, na primjer, uključuju zadatke automatske kontrole nekoliko procesa.

Pravi paralelizam se postiže samo kada se zadaci ovog tipa implementiraju na višeprocesorski sistem, kada je moguće izvršiti svaki proces od strane posebnog procesora. Jednoprocesorski sistemi simuliraju paralelizam dijeleći procesorsko vrijeme između zadataka za kontrolu različitih procesa. U zavisnosti od tipa operativnog sistema koji se koristi (jednostruko ili višeprogramirani), deljenje vremena se može izvršiti ili od strane sistema koji se razvija (kao u MS DOS-u) ili od operativnog sistema koji se koristi (kao u Windows sistemima).

Održivost- svojstvo apstrakcije da postoji u vremenu nezavisno od procesa koji je generisao dati softverski objekat, i/ili u prostoru, krećući se iz adresnog prostora u kojem je kreiran.

razlikovati:

1) privremeni objekti koji pohranjuju međurezultate nekih radnji, na primjer, proračune;

2) lokalni objekti koji postoje unutar potprograma, čiji se životni vijek računa od poziva potprograma do njegovog završetka;

3) globalno objekti koji postoje dok se program učitava u memoriju;

4) konzervirano objekte čiji su podaci pohranjeni u eksternim memorijskim datotekama između programskih sesija.

Svi gore navedeni principi implementirani su u jednoj ili drugoj mjeri u različitim verzijama objektno orijentiranih jezika.

Voljom sudbine moram da pročitam poseban kurs o šablonima dizajna na fakultetu. Specijalni kurs je obavezan, pa mi studenti dolaze veoma različiti. Naravno, među njima ima i programera u praksi. Ali, nažalost, većina ljudi ima poteškoća čak i da razumije osnovne pojmove OOP-a.

Da bih to uradio, pokušao sam da objasnim osnovne koncepte OOP-a (klasa, objekat, interfejs, apstrakcija, enkapsulacija, nasleđivanje i polimorfizam) koristeći manje ili više živih primera.

Prvi dio ispod je o klasama, objektima i interfejsima.
Drugi dio ilustruje inkapsulaciju, polimorfizam i nasljeđivanje

Osnovni koncepti OOP-a

Klasa
Zamislite da dizajnirate automobil. Znate da auto mora imati motor, ovjes, dva fara, 4 kotača itd. Takođe znate da vaš automobil mora biti u stanju da se podigne i uspori, okrene i unazad. I, što je najvažnije, tačno znate kako motor i kotači međusobno djeluju, prema kojim se zakonima kreću bregasto vratilo i radilica, kao i kako su raspoređeni diferencijali. Uvjereni ste u svoje znanje i počnite dizajnirati.

Opisujete sve dijelove koji čine vaše vozilo i kako ti dijelovi međusobno djeluju. Pored toga, opisujete šta korisnik mora da uradi da natera automobil da zakoči ili da upali duga svetla. Rezultat vašeg rada bit će neka skica. Upravo ste razvili ono što OOP naziva Klasa.

Klasa To je način opisa entiteta, definisanje stanja i ponašanja u zavisnosti od ovog stanja, kao i pravila za interakciju sa ovim entitetom (ugovor).

Sa programske tačke gledišta, klasa se može posmatrati kao skup podataka (polja, atributi, članovi klase) i funkcija za rad sa njima (metode).

Sa stanovišta strukture programa, klasa je složen tip podataka.

U našem slučaju, klasa će predstavljati entitet - automobil. Atributi klase će biti motor, ovjes, karoserija, četiri točka itd. Metode časa će biti „otvoriti vrata“, „pritisnuti papučicu gasa“, a takođe i „ispumpati deo benzina iz rezervoara za gas u motor“. Prve dvije metode su dostupne za izvršenje od strane drugih klasa (posebno klase "Driver"). Potonji opisuje interakcije unutar klase i nije dostupan korisniku.

U budućnosti, uprkos činjenici da se riječ "korisnik" povezuje sa Klondike Solitaire-om i Microsoft Wordom, korisnicima ćemo nazivati ​​one programere koji koriste vašu klasu, uključujući i vas. Osobu koja je autor klase zvaćemo programer.

Objekt
Uradili ste sjajan posao i mašine dizajnirane prema vašim crtežima silaze sa montažne trake. Evo ih, stoje u ravnim redovima u fabričkom dvorištu. Svaki od njih tačno replicira vaše crteže. Svi sistemi djeluju tačno onako kako ste dizajnirali. Ali svaki automobil je jedinstven. Svi imaju broj karoserije i motora, ali svi ovi brojevi su različiti, automobili se razlikuju po boji, a neki čak imaju i odljevke umjesto utisnutih diskova. Ovi automobili su u suštini objekti vaše klase.

Objekt (instanca) Je zaseban član klase sa specifičnim stanjem i ponašanjem koje je klasa u potpunosti definirala.

Jednostavno rečeno, objekt ima specifične vrijednosti atributa i metode koje rade na tim vrijednostima na osnovu pravila definiranih u klasi. U ovom primjeru, ako je klasa neki apstraktni automobil iz "svijeta ideja", onda je predmet određeni automobil koji stoji ispod vaših prozora.

Interfejs
Kada odemo do aparata za kafu ili sjednemo za volan, počinjemo komunicirati s njima. Obično se interakcija odvija uz pomoć određenog skupa elemenata: utor za prihvatanje novčića, dugme za odabir pića i pretinac za točenje čaše u aparatu za kafu; volan, pedale, ručica menjača u autu. Uvijek postoji ograničen skup kontrola s kojima možemo komunicirati.

Interfejs Je kolekcija metoda klase koja je dostupna za korištenje drugim klasama.

Očigledno, interfejs klase će biti skup svih njenih javnih metoda zajedno sa skupom javnih atributa. U osnovi, sučelje specificira klasu, jasno definirajući sve moguće akcije na njoj.
Dobar primjer interfejsa bi bila kontrolna tabla automobila, koja vam omogućava da pozovete metode kao što su ubrzavanje, kočenje, skretanje, menjanje brzina, uključivanje farova itd. Odnosno, sve radnje koje druga klasa (u našem slučaju, vozač) može izvršiti u interakciji s automobilom.

Kada se opisuje interfejs klase, veoma je važno uspostaviti ravnotežu između fleksibilnosti i jednostavnosti. Klasa sa jednostavnim interfejsom biće laka za korišćenje, ali će postojati problemi koje neće moći da reši uz pomoć nje. U isto vrijeme, ako je sučelje fleksibilno, tada će se, najvjerovatnije, sastojati od prilično složenih metoda s velikim brojem parametara koji će vam omogućiti da uradite mnogo, ali korištenje će biti ispunjeno velikim poteškoćama i rizikom napraviti grešku, nešto zbunjujuće.

Primer jednostavnog interfejsa je mašina sa automatskim menjačem. Svaka plavuša koja je završila dvonedeljni kurs vožnje moći će vrlo brzo da savlada njen menadžment. S druge strane, potrebno je nekoliko mjeseci ili čak godina naporne obuke da bi se savladalo upravljanje modernim putničkim avionom. Ne bih volio da budem u Boeingu kojim upravlja čovjek sa dvije sedmice letačkog iskustva. S druge strane, nikada nećete natjerati automobil da poleti i odleti iz Moskve za Washington.

Svi objektno orijentisani jezici koriste tri osnovna principa objektno orijentisanog programiranja:

  • Enkapsulacija... Kako ovaj jezik sakriva suštinske karakteristike implementacije objekta?
  • Nasljedstvo... Kako ovaj jezik pruža mogućnost ponovnog korištenja programskog koda?
  • Polimorfizam... Kako vam ovaj jezik omogućava da tumačite povezane objekte na uniforman način?

Prvi princip OOP-a je inkapsulacija. Enkapsulacija To je programski mehanizam koji povezuje kod i podatke kojima manipulira, štiti ih od vanjskog pristupa i zloupotrebe i skriva detalje implementacije pomoću jezika. Na primjer, pretpostavimo da koristimo klasu koja predstavlja objekte tipa Pen. Takva klasa obuhvata intrinzičnu sposobnost objekata da crtaju tačke, linije i oblike različite debljine i boje. Princip enkapsulacije omogućava vam da pojednostavite zadatak programiranja u smislu da više ne morate da brinete o višestrukim linijama koda koji obavljaju posao klase nib iza scene. Sve što je potrebno je instancirati klasu nib i stupiti u interakciju s njom pozivanjem njenih funkcija.

Zaštita podataka je važan aspekt enkapsulacije. U idealnom slučaju, podaci koji karakteriziraju stanje objekta trebali bi biti definirani kao privatni i nedostupni vanjskom okruženju. U ovom slučaju, eksterno okruženje objekta će biti prinuđeno da zatraži pravo da promeni ili pročita odgovarajuće vrednosti. Dakle, koncept enkapsulacije odražava opšte pravilo da polja podataka objekta ne bi trebalo da budu direktno dostupna sa javnog interfejsa. Ako korisnik treba promijeniti stanje objekta, onda to treba učiniti ne direktno, već indirektno, koristeći funkcije čitanja ( dobiti()) i modifikacije ( set()). U C #, dostupnost podataka je implementirana na nivou sintakse pomoću ključnih riječi javnosti, privatni, zaštićeno, i zaštićeno interno.

Unutar objekta, kod, podaci ili i kod i podaci mogu biti privatni za druge objekte ili javni. Privatni kod i podaci su poznati i dostupni iz drugog dijela samo ovog objekta (tj. samo samog objekta). Stoga se privatnom kodu i podacima ne može pristupiti iz onog dijela programa koji postoji izvan datog objekta.

Sljedeći OOP princip je nasljeđe , što znači sposobnost jezika da obezbijedi konstrukciju definicija novih klasa na osnovu definicija postojećih klasa. U suštini, nasljeđivanje vam omogućava da proširite ponašanje osnovne klase (također tzv roditeljska klasa) izgradnjom podklase (tzv derivat ili dječiji razred) koji nasljeđuje karakteristike i funkcionalnost roditeljske klase. U suštini, ovaj oblik nasljeđivanja je ponovna upotreba programskog koda jedne (bazne) klase u drugim (iz nje izvedenim) klasama. Tipično, u ovom slučaju, podređena klasa proširuje mogućnosti osnovne klase dodavanjem nekih novih mogućnosti koje nisu dostupne u osnovnoj klasi. Ovaj oblik nasljeđivanja naziva se "je-a" (to jest, biti isti, ali s više mogućnosti).


Drugi oblik ponovne upotrebe koda je model lokalizacije/delegiranja (također poznat kao odnos ima-lokalizacija). Ovaj obrazac se ne koristi za kreiranje odnosa klasa-podklasa. Umjesto toga, klasa može definirati u svom sastavu neku varijablu druge klase i izložiti dio ili cijelu svoju funkcionalnost vanjskom okruženju. U ovom slučaju, klasa je više kao kontejner koji sadrži instance drugih klasa.

Treći princip OOP-a je polimorfizam ... Karakterizira sposobnost jezika da interpretira povezane objekte na isti način. Ova karakteristika objektno orijentisanog jezika omogućava osnovnoj klasi da definiše više članova za sve izvedene klase. Formalno, ovaj zajednički član se zove polimorfni interfejs. Polimorfni interfejs za klasu se konstruiše definisanjem nekog proizvoljnog broja virtuelno i apstraktno funkcije. Funkcija virtuelne klase mogu promjena u izvedenoj klasi i apstraktnoj funkciji može biti samo nadjačati. Kada izvedene klase nadjačavaju funkcije definirane u osnovnoj klasi, one u suštini nadjačavaju svoj odgovor na odgovarajući zahtjev. Pored mogućnosti zaobilaženja funkcija, C # pruža mogućnost korištenja drugog oblika polimorfizma - preopterećenja funkcija. Preopterećenje treba posmatrati kao dodatnu priliku za razlikovanje funkcija sa istim imenom, koje se razlikuju po broju ili vrsti argumenata. Stoga se preopterećenje može primijeniti ne samo na funkcije - članove klase, već i na globalne funkcije.

Ne mogu programirati na objektno orijentisanim jezicima. Nisam naučio. Nakon 5 godina industrijskog Java programiranja, još uvijek ne znam kako da napravim dobar objektno orijentisan sistem. jednostavno ne razumijem.

Pokušao sam da naučim, iskreno. Proučavao sam obrasce, čitao kod projekata otvorenog koda, pokušavao u svojoj glavi izgraditi koherentne koncepte, ali još uvijek nisam razumio principe kreiranja visokokvalitetnih objektno orijentiranih programa. Možda ih je neko drugi razumio, ali ja ne.

I evo nekoliko stvari koje me zbunjuju.

Ne znam šta je OOP

Ozbiljno. Teško mi je formulisati glavne ideje OOP-a. Jedna od glavnih ideja u funkcionalnom programiranju je apatridnost. Strukturno, to je dekompozicija. U modularnoj, funkcionalnoj podjeli na kompletne blokove. U bilo kojoj od ovih paradigmi, dominantni principi se primjenjuju na 95% koda, a jezik je dizajniran da podstiče njihovu upotrebu. Za OOP ne znam takva pravila.
  • Apstrakcija
  • Enkapsulacija
  • Nasljedstvo
  • Polimorfizam
Zvuči kao skup pravila, zar ne? Dakle, to je to, sama pravila koja se moraju poštovati 95% vremena? Hmm, pogledajmo izbliza.

Apstrakcija

Apstrakcija je moćan alat za programiranje. To je ono što nam omogućava da izgradimo velike sisteme i zadržimo kontrolu nad njima. Malo je vjerovatno da bismo se ikada približili sadašnjem nivou programa da nismo naoružani takvim alatom. Međutim, kako se apstrakcija može usporediti s OOP-om?

Prvo, apstrakcija nije atribut isključivo OOP-a, pa čak ni programiranja općenito. Proces stvaranja nivoa apstrakcije proteže se na gotovo sve oblasti ljudskog znanja. Dakle, možemo donositi sudove o materijalima ne ulazeći u detalje njihove molekularne strukture. Ili pričajte o predmetima bez pominjanja materijala od kojih su napravljeni. Ili da govorimo o složenim mehanizmima, kao što su kompjuter, avionska turbina ili ljudsko tijelo, a da se ne sjećaju pojedinačnih detalja ovih entiteta.

Drugo, oduvijek su postojale apstrakcije u programiranju, počevši od beleški Ade Lovelace, koja se smatra prvom programerkom u istoriji. Od tada, ljudi neprestano stvaraju apstrakcije u svojim programima, često imaju samo najjednostavnije alate za to. Dakle, Abelson i Sussman u svojoj poznatoj knjizi opisuju kako da naprave sistem za rješavanje jednačina uz podršku kompleksnih brojeva, pa čak i polinoma, koji u svom arsenalu imaju samo procedure i povezane liste. Dakle, s kojim dodatnim sredstvima apstrakcije dolazi OOP? Nemam pojma. Isticanje koda u potprograme? To može učiniti bilo koji jezik visokog nivoa. Kombinovanje potprograma na jednom mestu? Za to ima dovoljno modula. Tipkanje? Bilo je to mnogo prije PLO-a. Primer sa sistemom za rešavanje jednačina dobro pokazuje da konstrukcija nivoa apstrakcije ne zavisi toliko od sredstava jezika koliko od sposobnosti programera.

Enkapsulacija

Glavni adut enkapsulacije je skrivanje implementacije. Klijentski kod vidi samo sučelje i može se osloniti samo na njega. Ovo oslobađa ruke programerima koji bi mogli odlučiti promijeniti implementaciju. I to je stvarno super. Ali opet, pitanje je kakve veze OOP ima s tim? Sve gore navedene paradigme podrazumijevaju skrivanje implementacije. Kada programirate u C-u, vi dodjeljujete interfejs u datoteke zaglavlja, Oberon vam omogućava da polja i metode napravite lokalnim modulu, i konačno, u mnogim jezicima, apstrakcija se gradi jednostavno kroz potprograme koji takođe inkapsuliraju implementaciju. Štaviše, često su i sami objektno orijentisani jezici krše pravilo enkapsulacije, omogućavajući pristup podacima putem posebnih metoda - gettera i settera u Javi, svojstava u C# itd. (U komentarima smo otkrili da neki objekti u programskim jezicima nisu objekti sa stanovišta OOP-a: objekti prijenosa podataka su isključivo odgovorni za prijenos podataka, te stoga nisu punopravni OOP entiteti, te stoga , nema potrebe da održavaju enkapsulaciju. , metode pristupa su najbolje očuvane da bi arhitektura bila fleksibilna. Ovako je to komplikovano.) Štaviše, neki objektno orijentisani jezici, kao što je Python, ne pokušavaju da sakriju ništa na sve, ali se oslanjajte isključivo na mudrost programera koji koriste ovaj kod.

Nasljedstvo

Nasljeđivanje je jedna od rijetkih novih stvari koja je zaista došla na scenu zahvaljujući OOP-u. Ne, objektno orijentisani jezici nisu stvorili novu ideju - nasljeđivanje se može lako implementirati u bilo koju drugu paradigmu - ali OOP je po prvi put doveo ovaj koncept na nivo samog jezika. Prednosti nasljeđivanja su također očigledne: kada vi skoro odgovara nekoj klasi, možete kreirati potomka i nadjačati neke njegove funkcionalnosti. U jezicima koji podržavaju višestruko nasljeđivanje, kao što su C++ ili Scala (kod ovog drugog, na račun osobina), pojavljuje se još jedan slučaj upotrebe - miksini, male klase koje vam omogućavaju da "miješate" funkcionalnost u novu klasu bez kopiranje koda.

Dakle, to je to – šta OOP izdvaja kao paradigmu od drugih? Hmm... ako je tako, zašto ga tako rijetko koristimo u stvarnom kodu? Sjećate li se kada sam govorio o tome da 95% kodeksa poštuje pravila dominantne paradigme? Nisam se šalio. U funkcionalnom programiranju, najmanje 95% koda koristi nepromjenjive podatke i funkcije bez nuspojava. Kod modularnog, skoro sav kod je logički upakovan u module. Zagovornici strukturiranog programiranja, slijedeći Dijkstrina pravila, pokušavaju sve dijelove programa razbiti na male dijelove. Nasljeđivanje je mnogo rjeđe. Možda u 10% koda, možda u 50%, u nekim slučajevima (na primjer, kod nasljeđivanja od klasa okvira) - u 70%, ali ne više. Jer u većini situacija je lako nema potrebe.

Štaviše, nasledstvo opasno za dobar dizajn. Toliko opasna da Grupa četvorice (naizgled propovjednici PLO-a) u svojoj knjizi preporučuju zamjenu delegiranja kad god je to moguće. Nasljeđe kakvo postoji u današnjim popularnim jezicima dovodi do krhkog dizajna. Nakon što je naslijedila od jednog pretka, klasa više ne može naslijediti od drugih. Promjena pretka također postaje opasna. Postoje, naravno, privatni/zaštićeni modifikatori, ali oni također zahtijevaju jake psihičke sposobnosti da se pogodi kako se klasa može promijeniti i kako je klijentski kod može koristiti. Nasljeđivanje je toliko opasno i nezgodno da ih veliki okviri (kao što su Spring i EJB u Javi) napuštaju, prelazeći na druge alate koji nisu objektno orijentisani (kao što je metaprogramiranje). Posljedice su toliko nepredvidive da neke biblioteke (kao što je Guava) svojim klasama propisuju modifikatore koji zabranjuju nasljeđivanje, a u novom Go jeziku odlučeno je da se hijerarhija nasljeđivanja potpuno napusti.

Polimorfizam

Možda je polimorfizam najbolja stvar u objektno orijentiranom programiranju. Zahvaljujući polimorfizmu, objekat tipa Person na izlazu izgleda kao "Shandorkin Adam Impolitovich", a objekat tipa Point izgleda kao "". On vam omogućava da napišete "Mat1 * Mat2" i dobijete proizvod matrica, sličan proizvodu običnih brojeva. Bez toga, ne bi bilo moguće čitati podatke iz ulaznog toka, bez obzira da li dolaze iz mreže, datoteke ili niza u memoriji. Gdje god postoje interfejsi, polimorfizam se podrazumijeva.

Zaista volim polimorfizam. Tako da o njegovim problemima neću ni govoriti na mainstream jezicima. Također ću prećutati o uskosti pristupa dispečeru samo tipa i o tome kako bi se to moglo učiniti. Većinu vremena radi kako treba, što je dovoljno dobro. Pitanje je: da li je polimorfizam sam princip koji razlikuje OOP od drugih paradigmi? Da ste me pitali (a pošto čitate ovaj tekst, onda možete pretpostaviti da ste pitali), odgovorio bih „ne“. A razlog je isti postotak upotrebe u kodu. Možda su interfejsi i polimorfne metode malo češći od nasljeđivanja. Ali uporedite broj redova koda koji zauzimaju sa brojem redova napisanih uobičajenim proceduralnim stilom - potonjih uvijek ima više. Gledajući jezike koji podstiču ovaj stil programiranja, ne mogu ih nazvati polimorfnim. Jezici sa podrškom za polimorfizam - da, u redu je. Ali ne i polimorfni jezici.

(Međutim, ovo je moje mišljenje. Uvijek se možete ne složiti.)

Dakle, apstrakcija, enkapsulacija, nasljeđivanje i polimorfizam su sve u OOP-u, ali ništa od toga nije inherentno njemu. Šta je onda OOP? Vjeruje se da suština objektno orijentiranog programiranja zapravo leži u objektima (zvuči sasvim logično) i klasama. To je ideja kombinovanja koda i podataka, kao i ideja da objekti u programu odražavaju entitete stvarnog sveta. Kasnije ćemo se vratiti na ovo mišljenje, ali prvo ćemo staviti tačke na i.

Čiji je OOP hladniji?

Iz prethodnog odjeljka možete vidjeti da se programski jezici mogu veoma razlikovati po načinu na koji implementiraju objektno orijentirano programiranje. Ako uzmete ukupnost svih implementacija OOP-a na svim jezicima, onda najvjerovatnije nećete pronaći uopće jednu osobinu zajedničku za sve. Da bih nekako ograničio ovaj zoološki vrt i razjasnio razmišljanje, fokusiraću se samo na jednu grupu - čisto objektno orijentisane jezike, naime Java i C #. Termin "čisto objektno orijentisan" u ovom slučaju znači da jezik ne podržava druge paradigme ili ih implementira kroz isti OOP. Python ili Ruby, na primjer, neće biti čisti, budući da možete lako napisati kompletan program na njima bez ijedne deklaracije klase.

Da bismo bolje razumeli suštinu OOP-a u Javi i C#, hajde da pogledamo primere implementacije ove paradigme na drugim jezicima.

Mali razgovor. Za razliku od svojih modernih kolega, ovaj jezik je bio dinamički kucan i koristio je stil prenošenja poruka za implementaciju OOP-a. Umjesto poziva metoda, objekti su slali poruke jedni drugima, a ako primalac nije mogao obraditi ono što je stiglo, on je jednostavno proslijedio poruku nekom drugom.

Common Lisp. CL je prvobitno slijedio istu paradigmu. Zatim su programeri odlučili da će biti potrebno predugo za pisanje `(send obj" some-message) `, i pretvorili su notaciju u poziv metode -` (some-method obj) `. Danas Common Lisp ima razvijen sistem objekata -orijentisano programiranje (CLOS) s podrškom za višestruko nasljeđivanje, multimetode i metaklase. Karakteristična karakteristika je da se OOP u CL ne vrti oko objekata, već oko generičkih funkcija.

Clojure. Clojure ima čak 2 objektno orijentisana programska sistema - jedan naslijeđen iz Jave, a drugi, baziran na više metoda i sličniji CLOS-u.

R. Ovaj jezik za statističku analizu podataka takođe ima 2 objektno orijentisana programska sistema - S3 i S4. Oba su naslijeđena iz S jezika (što nije iznenađujuće, s obzirom da je R implementacija komercijalnog S-a otvorenog koda). S4 uglavnom odgovara OOP implementacijama u modernim mainstream jezicima. S3 je lakša verzija, elementarno implementirana pomoću samog jezika: kreirana je jedna zajednička funkcija koja šalje zahtjeve pomoću atributa "class" primljenog objekta.

JavaScript. Ideološki sličan Smalltalku, iako koristi drugačiju sintaksu. Umjesto nasljeđivanja, koristi prototip: ako željeno svojstvo ili pozvana metoda nije u samom objektu, tada se zahtjev prosljeđuje objektu prototipa (svojstvo prototipa svih JavaScript objekata). Zanimljiva činjenica je da se ponašanje svih objekata klase može promijeniti zamjenom jedne od metoda prototipa (na primjer, dodavanje metode `.toBASE64` za string klasu izgleda vrlo lijepo).

Python. Općenito, pridržava se istog koncepta kao i mainstream jezici, ali također podržava prosljeđivanje traženja atributa drugom objektu, kao u JavaScript-u ili Smalltalku.

Haskell. U Haskell-u uopšte ne postoji stanje, a samim tim ni objekti u uobičajenom smislu. Ipak, još uvijek postoji neka vrsta OOP-a: tipovi podataka (tipovi) mogu pripadati jednoj ili više klasa tipova. Na primjer, skoro svi tipovi u Haskell-u su u klasi Eq (odgovorni za poređenje 2 objekta), a svi brojevi su dodatno u klasama Num (operacije nad brojevima) i Ord (operacije<, <=, >=,>). U mainstream jezicima, klase (podaci) odgovaraju tipovima, a interfejsi klasama tipa.

Sa državljanstvom ili bez državljanstva?

Ali da se vratimo na uobičajenije objektno orijentisane sisteme programiranja. Ono što nikada nisam mogao da shvatim je odnos objekata prema unutrašnjem stanju. Prije proučavanja OOP-a, sve je bilo jednostavno i transparentno: postoje strukture koje pohranjuju nekoliko povezanih podataka, postoje procedure (funkcije) koje ih obrađuju. prošetati (pas), povući (račun, iznos). Onda su došli predmeti, a takođe nije bilo ništa (iako je postalo mnogo teže čitati programe - moj pas je šetao [koga?], a račun je podizao novac [odakle?]). Tada sam saznao za skrivanje podataka. I dalje sam mogao šetati psa, ali nisam mogao vidjeti sastav njegove hrane. Hrana nije izvršila nikakvu radnju (vjerovatno biste mogli napisati koju hranu treba jesti (pas), ali ja ipak više volim da moj pas jede hranu nego obrnuto). Hrana je samo podatak, a meni (i mom psu) samo trebamo pristupiti. Sve jednostavno... Ali više nije bilo moguće uklopiti se u okvire paradigme, kao u stare farmerke s kraja 90-ih.

U redu, imamo metode pristupa podacima. Hajdemo na ovu malu samoobmanu i pretvarajmo se da su naši podaci zaista skriveni. Ali sada znam da su objekti prije svega podaci, a onda, možda, metode koje ih obrađuju. Shvatio sam kako pisati programe, čemu treba težiti prilikom dizajniranja.

Pre nego što sam stigao da uživam u prosvetljenju, video sam reč bez državljanstva na internetu (kunem se da je bila okružena sjajem, a bio je oreol iznad slova t i l). Kratko proučavanje literature otvorilo je predivan svijet transparentnog toka kontrole i jednostavnog višenitnog rada bez potrebe za praćenjem konzistentnosti objekta. Naravno, odmah sam poželeo da dodirnem ovaj divni svet. Međutim, to je značilo potpuno napuštanje bilo kakvih pravila - sada nije bilo jasno da li pas treba sam hodati ili je za to bio potreban poseban WalkManager; Da li vam je potreban račun ili će Banka obaviti sav posao, a ako jeste, onda treba da otpiše novac statički ili dinamički itd. Broj slučajeva upotrebe je eksponencijalno rastao, a sve opcije u budućnosti mogle bi dovesti do potrebe za ozbiljnim refaktorom.

Još uvijek ne znam kada objekt treba učiniti bez stanja, kada ima status, a kada samo kontejner podataka. Ponekad je to očigledno, ali češće nije.

Tipkanje: statično ili dinamičko?

Još jedna stvar koju ne mogu sasvim da shvatim u vezi sa jezicima kao što su C# i Java je da li su statički ili dinamički kucani. Vjerovatno će većina ljudi uskliknuti: „Kakva glupost! Naravno, statički otkucani! Tipovi se provjeravaju u vrijeme kompajliranja!" Ali da li je to zaista tako jednostavno? Da li je tačno da programer, upisujući tip X u parametre metode, može biti siguran da će mu objekti tipa X uvijek biti proslijeđeni? Tako je – ne može, jer metodi X može se proslijediti parametar tipa X ili njegovog naslednika... Činilo bi se, pa šta? Nasljednici klase X i dalje će imati iste metode kao i X. Metode po metodama, ali logika rada može biti potpuno drugačija. Najčešći slučaj je kada se pokaže da je podređena klasa optimizirana za druge potrebe osim X, a naša metoda može računati upravo na tu optimizaciju (ako vam se takav scenarij čini nerealnim, pokušajte napisati dodatak za neku razvijenu open source biblioteku - ili ćete provesti nekoliko sedmica da analizirate arhitekturu i algoritme biblioteke, ili ćete samo nasumično pozvati metode sa odgovarajućim potpisom). Kao rezultat toga, program radi, ali brzina rada pada za red veličine. Iako sa stanovišta kompajlera, sve je tačno. Značajno je da Scala, koja se naziva nasljednikom Jave, na mnogim mjestima po defaultu dozvoljava prosljeđivanje samo argumenata specificiranog tipa, iako se ovo ponašanje može promijeniti.

Drugi problem je null, koja se može proslijediti umjesto gotovo bilo kojeg objekta u Javi i umjesto bilo kojeg objekta koji se može nulirati u C #. null pripada svim tipovima odjednom, a u isto vrijeme ne pripada nijednom od njih. null nema polja ili metode, tako da svaki njegov poziv (osim provjere null) rezultira greškom. Čini se da su svi navikli na ovo, ali poređenja radi, Haskell (i ista Scala) će biti primorani da koristi posebne tipove (Možda u Haskell-u, Option u Scali) za premotavanje funkcija koje bi mogle vratiti null u drugim jezicima. Kao rezultat toga, ljudi često kažu za Haskell „teško je sastaviti program u njemu, ali ako je uspio, onda najvjerovatnije radi ispravno“.

S druge strane, mainstream jezici, očigledno, nisu dinamički tipizirani, pa stoga nemaju svojstva kao što su jednostavnost interfejsa i fleksibilnost procedura. Kao rezultat toga, pisanje u Python ili Lisp stilu također postaje nemoguće.

Koja je razlika kako se ovo kucanje zove ako su sva pravila ionako poznata? Razlika je u tome s koje strane pristupiti arhitektonskom dizajnu. Postoji dugogodišnja debata o tome kako izgraditi sistem: raditi mnogo tipova i nekoliko funkcija, ili nekoliko tipova i mnogo funkcija? Prvi pristup se široko koristi u Haskell-u, drugi u Lisp-u. Moderni objektno orijentirani jezici koriste nešto između. Ne želim da kažem da je ovo loše – verovatno ima svoje prednosti (na kraju, ne zaboravite da su Java i C# višejezične platforme), ali svaki put kada počinjem novi projekat razmišljam o tome odakle da počnem da dizajniram – sa vrste ili iz funkcionalnog.

I dalje...

Ne znam kako da modeliram problem. Vjeruje se da OOP omogućava prikaz objekata stvarnog svijeta u programu. Međutim, u stvarnosti imam psa (sa dva uha, četiri šape i ogrlicu) i bankovni račun (sa menadžerom, službenicima i pauzom za ručak), a u programu su VygulManager, AccountFabrika...pa, shvatili ste . I nije da program ima pomoćne klase koje ne odražavaju objekte iz stvarnog svijeta. Činjenica je da kontrolne promjene toka... WalkingManager oduzima zadovoljstvo šetnje psa, a ja dobijam novac sa bezdušnog bankovnog računa (hej, gdje je ona slatka djevojka za koju sam promijenio novac prošle sedmice?).

Možda sam snob, ali osjećao sam se mnogo bolje kada su podaci u kompjuteru bili samo podaci, čak i ako su opisivali mog psa ili bankovni račun. Sa podacima sam mogao da radim šta god mi je zgodno, bez gledanja u stvarni svet.

Također ne znam kako pravilno razložiti funkcionalnost. U Pythonu ili C++, ako mi je bila potrebna mala funkcija za pretvaranje stringa u broj, jednostavno sam je napisao na kraju datoteke. U Javi ili C #, moram ga premjestiti u zasebnu klasu StringUtils. Na jezicima koji nisu OO, mogao bih deklarirati ad hoc omot za vraćanje dvije vrijednosti iz funkcije (povučeni iznos i stanje na računu). U OOP jezicima, moram kreirati kompletnu klasu ResultTransaction. A za novu osobu na projektu (ili čak i mene za nedelju dana), ovaj čas će izgledati potpuno isto važno i fundamentalno u arhitekturi sistema. 150 fajlova, svi podjednako važni i fundamentalni - o, da, transparentna arhitektura, veliki nivoi apstrakcije.

Ne mogu pisati efikasne programe. Efikasni programi koriste malo memorije - inače će sakupljač smeća stalno usporavati izvršenje. Ali da biste izvršili najjednostavniju operaciju u objektno orijentisanim jezicima, morate kreirati desetak objekata. Da napravim jedan HTTP zahtjev, trebam kreirati objekat tipa URL, zatim objekat tipa HttpConnection, zatim objekat tipa Request... pa, shvatili ste. U proceduralnom programiranju, jednostavno bih pozvao nekoliko procedura, prenoseći im strukturu kreiranu na steku. Najvjerovatnije bi u memoriji bio kreiran samo jedan objekt - za pohranjivanje rezultata. U OOP-u, stalno moram zatrpati memoriju.

Možda je OOP zaista lijepa i elegantna paradigma. Možda jednostavno nisam dovoljno pametan da je razumem. Verovatno postoji neko ko može da napravi zaista lep program na objektno orijentisanom jeziku. Pa, mogu samo da im zavidim.

Top srodni članci