Piloni de programare orientată pe obiecte
C # poate fi considerat un nou membru al comunității de limbi de programare orientate pe obiecte, dintre care cele mai frecvente sunt Java, C ++, Object Pascal și (cu unele ipoteze) Visual Basic 6.0. În orice limbaj de programare orientat pe obiecte, sunt implementate în mod obligatoriu trei principii importante: "pilonul" programării orientate pe obiecte:
· Încapsulare: cum obiectele ascund dispozitivul intern;
· Moștenire: modul în care codul este reutilizat în această limbă;
· Polimorfism: cum suportă această limbă execuția acțiunii dorite, în funcție de tipul de obiect transferat?
Desigur, toate cele trei principii sunt implementate în C #. Cu toate acestea, înainte de a începe să analizăm caracteristicile sintactice ale punerii în aplicare a acestor principii, vom încerca să ne asigurăm că nu există absolut nicio ambiguitate în ele.
Primul "pilon" al programării orientate pe obiecte este încapsularea. Acesta este numele abilității de a ascunde detaliile implementării obiectelor de la utilizatorii acestor obiecte. De exemplu, să presupunem că ați creat o clasă numită DBReader (pentru lucrul cu o bază de date), în care sunt definite două metode principale: Open () și Close ().
// Clasa DBReader ascunde detaliile descoperirii prin încapsulare
// și închiderea bazelor de date
DBReader f = nou DBReader ();
// Realizăm acțiunile necesare cu baza de date
Clasa noastră fictivă DBReader încorporează detaliile interne ale exact așa cum detectează, încarcă, efectuează operații și în cele din urmă închide fișierul de date. Datorită încapsulării, programarea devine mai ușoară: nu trebuie să vă faceți griji cu privire la numărul mare de linii de cod care își îndeplinesc sarcina ascunsă de dvs. Tot ceea ce vi se cere este să creați o instanță a clasei cerute și să trimiteți mesajele necesare (cum ar fi "deschideți un fișier numit foo.mdf").
Cu filosofia încapsulării, un alt principiu este strâns legat: ascunderea tuturor datelor interne (adică, variabilele membre) ale clasei. Așa cum am spus, în mod ideal, toate variabilele interne ale clasei trebuie definite ca private. În consecință, apelul către aceștia din lumea exterioară va fi posibil numai prin funcții deschise - membri. Această soluție, printre altele, vă protejează de posibile erori, deoarece datele deschise sunt foarte ușor de deteriorat.
Moștenire: relația "a fi" și "a avea"
Următorul pilon al programării orientate pe obiecte este moștenirea. Aceasta înseamnă capacitatea de a crea noi definiții de clasă pe baza celor existente. De fapt, moștenirea vă permite să extindeți moștenirea de la clasa de bază în clasa proprie derivată. Un exemplu simplu al acestei abordări este prezentat în Fig. 3.3.
Fig. 3.3. Atitudinea "a fi"
După cum ne amintim, în partea de sus a oricărei ierarhii în .NET este întotdeauna obiectul de clasă de bază. În situația noastră, capacitățile acestei clase sunt în primul rând completate de oportunitățile introduse de clasa Shape. Acestea sunt proprietăți, câmpuri, metode și evenimente care sunt comune tuturor formelor geometrice. Clasa Hexagon (hexagon), derivată din Shape, completează capabilitățile celor două clase de bază anterioare cu proprietățile sale unice.
Diagrama din Fig. 3.3, poate fi citit după cum urmează: "Un hexagon este o figură geometrică, care este un obiect". Atunci când lazile dvs. sunt legate între ele prin relații de moștenire, aceasta înseamnă că relația stabilește o relație "să fie" între ele (este-a). Acest tip de relație se numește și moștenire clasică.
În lumea programării orientate pe obiecte, se folosește încă o utilizare a reutilizării codului. Această formă se numește incluziune-ștergere (sau relația "au-a"). În utilizarea sa, o clasă include o alta și deschide lumii din afară unele dintre capacitățile acestei clase interioare.
De exemplu, dacă creați un model software al unei mașini, este posibil să aveți ideea de a introduce un obiect radio în obiectul "mașină" folosind relația "au". Aceasta este o abordare foarte rezonabilă, deoarece este greu de realizat atât un radio din mașină, cât și o mașină de la radio, folosind relații de moștenire. În locul moștenirii, creați două clase independente care lucrează împreună, unde clasa exterioară (container) creează o clasă interioară și își deschide capabilitățile în lumea exterioară (Figura 3.4).
Fig. 3.4. Relația dintre timpul de executare și biblioteca de clasă .NET de bază
Obiect exterior Masina (sag) este responsabilă pentru crearea unui obiect radio intern. Dacă doriți să accesați obiectul Radio intern prin obiectul Sag, trebuie să furnizați o interfață deschisă specială în acest scop în clasa Mașină. Rețineți că utilizatorul obiectului Masina nu știe că transmite apelurile către un obiect intern:
// Clasa interioară Radio este încapsulată de clasa exterioară Car
Sag viper = mașină nouă ();
Viper.TurnOnRadio (fals); // Apelul va fi transferat la obiectul Radio intern
Polimorfism: clasic și pentru un caz specific
Ultimul pilon al programului de orientare obiect este polimorfismul. Se poate spune că acest termen determină posibilitățile inerente limbii, asupra interpretării obiectelor înrudite în același mod. Există două tipuri principale de polimorfism: polimorfismul clasic și polimorfismul "pentru un caz specific" (ad hoc). Polimorfismul clasic apare numai în limbile care suportă moștenirea clasică (inclusiv, bineînțeles, în C #). Cu polimorfismul clasic, puteți defini în clasa de bază un set de membri care pot fi înlocuiți în clasa derivată. Atunci când înlocuiți clasele derivate ale membrilor din clasa de bază, aceste clase derivate vor reacționa diferit la același tratament.
Pentru un exemplu, ne întoarcem din nou la ierarhia noastră de figuri geometrice. Să presupunem că forma de clasă (figura geometrică) definește Partidă funcție () - desen, care nu prezintă parametri și returnează nimic, deoarece formele geometrice sunt diferite, și fiecare tip de formă necesară pentru a reprezenta modul lor unic, cel mai probabil, vom avea nevoie în clasele derivate (cum ar fi hexagonal - Hexagon și cerc - cerc) pentru a crea propria metoda Draw (), înlocuindu-le Draw () metoda din clasa de bază (Figura 3.5.).
Fig. 3.5. Polimorfismul clasic
Polimorfismul clasic vă permite să determinați capacitățile tuturor claselor derivate atunci când creați o clasă de bază. De exemplu, în exemplul nostru, puteți fi sigur că metoda Draw () într-o formă sau alta este prezentă în orice clasă derivată din Shape. Avantajele polimorfismului clasic poate include, de asemenea, faptul că, în multe cazuri, puteți evita crearea unui duplicat metode pentru a efectua operațiuni similare (cum ar DrawCircle (), DrawRectangleO, DrawHexagon () și așa mai departe. D.).
Al doilea tip de polimorfism este polimorfismul pentru un caz specific (polimorfism ad-hoc). Acest tip de polimorfism vă permite să vă referiți în mod similar la obiecte care nu sunt legate de moștenirea clasică. Acest lucru este realizat prin foarte simplu. În fiecare dintre aceste obiecte trebuie să aibă o metodă cu aceeași semnătură (de exemplu, același nume al metodei, acceptă un parametru și să se întoarcă de tip în limbi care acceptă polimorfismul acestui tip de tehnologie este folosită „legarii» (târziu obligatoriu), atunci când tipul de obiect care este accesat, devine clar numai în cursul programului. în funcție de ce tip ne întoarcem, a cauzat metoda potrivită. ca un exemplu, ia în considerare circuitul din Fig. 3.6.
Rețineți că strămoșul comun - clasa de bază pentru CCircle, SNegakon și CRectangle nu există. Cu toate acestea, fiecare clasă are o metodă Draw () cu aceeași semnătură. Pentru a demonstra utilizarea acestui tip de polimorfism în cod real, vom folosi un exemplu în Visual Basic 6.0. Înainte de inventarea VB.NET, Visual Basic nu a sprijinit polimorfismul clasic (ca și moștenirea clasică), forțând dezvoltatorii să își concentreze eforturile asupra polimorfismului ad-hoc.
Fig. 3.6. Polimorfism pentru un anumit caz
'Acesta este codul Visual Basic 6.0!
"Mai întâi, creați o serie de elemente de tip Object și setați elementul de referință pentru fiecare element
Dim objArr (3) ca obiect
Setați objArr (0) = Cicluri noi
Setați objArr (1) = Chexagon nou
Setați objArr (2) = Cicluri noi
Setați objArr (3) = Creutangel nou
"Acum, cu ajutorul unui ciclu, vom forța fiecare element să se deseneze
Dimit ca Integer
objArr (i). Draw () 'Legarea ulterioară
În acest cod, am creat mai întâi o serie de elemente de tip Object (acesta este tipul de date încorporat din Visual Basic 6.0 pentru stocarea referințelor la orice obiecte care nu au nimic în comun cu clasa System.Object din .NET). Am legat apoi fiecare element al matricei de un obiect de tip corespunzător și apoi am folosit metoda Draw () pentru fiecare dintre aceste obiecte utilizând o buclă. Rețineți că formele geometrice - elementele de matrice - nu au o clasă de bază comună cu implementarea metodei Draw () în mod implicit.
O revizuire teoretică a principalelor principii ale polimorfismului - încapsulare, moștenire și polimorfism în acest sens este completă. Desigur, C # implementează toate aceste principii, în timp ce C # suportă atât relațiile "fi" cât și relațiile "have" pentru reutilizarea codului și ambele varietăți de polimorfism. Acum, sarcina noastră este să aflăm cum fiecare dintre aceste principii este implementat utilizând sintaxa C #.
Instrumente de încapsulare în C #
Principiul de încapsulare implică faptul că nu puteți accesa datele interne ale unui obiect (variabile membre) direct printr-o instanță a acestui obiect. În schimb, trebuie să utilizați metode speciale pentru a obține informații despre starea internă a obiectului și pentru a efectua modificări. În C #, încapsularea este implementată la nivel de sintaxă cu ajutorul cuvintelor cheie publice, private și protejate. De exemplu, considerăm următoarea definiție a clasei:
// Clasă cu un singur câmp
clasa publica
public intOfPages;
Termenul "câmp" este folosit pentru datele publice ale variabilelor de clasă declarate cu cuvântul cheie public. Când utilizați câmpuri în aplicație, apare o problemă: puteți atribui o valoare unui câmp și este destul de dificil să organizați verificarea acestei valori pentru logica de afaceri a aplicației. De exemplu, numărul nostru variabil openOfPages utilizează tipul de date int. Valoarea maximă pentru acest tip de date este destul de mare (2,147,483,647). Dacă există un astfel de cod în program, nu vor exista probleme din partea compilatorului:
static public void Principalul ()
Rezervați miniNovel = carte nouă ();
În conformitate cu principiul încapsulării, vă permite să protejați datele clasei interne de daune neintenționate. Pentru a face acest lucru, toate datele interne trebuie să fie închise (declarând variabilele interne utilizând cuvintele cheie private sau protejate). Pentru a accesa datele interne, puteți utiliza una din următoarele două metode:
· Crearea unei perechi tradiționale de metode - una pentru obținerea informațiilor (accessor), a doua pentru efectuarea de modificări (mutator);
· Definirea unei proprietăți denumite.
O altă metodă de protejare a datelor oferită de C # este folosirea cuvântului cheie readonly. Cu toate acestea, indiferent de metoda pe care o alegeți, principiul general rămâne același - clasa încapsulată trebuie să ascundă detaliile implementării sale din lumea exterioară. Această abordare este adesea numită programare cutie neagră. Un alt avantaj al acestei abordări este că vă puteți îmbunătăți în mod arbitrar implementarea internă a clasei dvs. prin schimbarea completă a conținutului acesteia. Singurul lucru pe care va trebui să-l ocupați este că în noua implementare există metode cu aceeași semnătură și funcționalitate ca în versiunile anterioare. În acest caz, nu trebuie să modificați nicio linie de cod existent în afara acestei clase.