Programare orientata pe obiect din perspectiva ingineriei software

Sizin üçün oyun:

Google Play'də əldə edin


Yüklə 0.61 Mb.
tarix01.11.2017
ölçüsü0.61 Mb.



Programare orientata pe obiect din perspectiva ingineriei software :

Dezvoltarea orientata pe obiect a aplicatiilor


Mihai Popescu si Mazilu Razvan

Grupa 442A

Cuprins:

 

Introducere



  Limbaje ce permit programarea obiect-orientata

  Diagrame UML


  Pasii dezvoltarii obiect-orientate a aplicatiilor

  Compararea dezvoltarii obiect-orientate cu dezvoltarile traditionale



  Concluzii


Introducere
Modalitatile (tehnici, paradigme) de programare au evoluat de-a lungul anilor, reflectând trecerea de la programe de dimensiuni reduse la programe si aplicatii de dimensiuni foarte mari, pentru coordonarea carora sunt necesare tehnici evoluate.
Software-ul de dimensiuni mari, care nu poate fi realizat de o singura persoana, intra în categoria sistemelor complexe, alaturi de alte sisteme complexe din cele mai variate domenii, cum sunt organizarea materiei sau organizarile sociale. 
Situatiile reale si experiente ale psihologilor au relevat limitele capacitatii umane în perceptia sistemelor complexe, adica imposibilitatea unei persoane de percepe si controla un numar mare de entitati de informatie simultan. De aceea, descompunerea si organizarea sistemelor complexe, în scopul de putea fi percepute, proiectate sau conduse este esentiala. Ordinea în sistemele complexe este introdusa în general printr-o organizare ierarhica, pe mai multe tipuri si nivele de ierarhie. În reprezentarea ierarhica a sistemelor complexe se evidentiaza doua tipuri de ierarhii: ierarhia structurala sau de compozitie si ierarhia de tip. 
Ierarhia structurala este o ierarhie în care se poate afirma despre un obiect ca este o parte a altui obiect, mai complex. Exemple de astfel de descompuneri se pot da oricâte, din orice domeniu. De exemplu, un calculator poate fi studiat prin descompunerea lui în subansamble componente: placa de baza, placa video, monitor, etc; la rândul ei, placa de baza este compusa din placheta de circuit imprimat, procesor, memorie, etc. Aceasta este o ierarhie de tipul “este o parte din…”. 
Pe de alta parte, fiecare obiect poate fi încadrat într-o categorie (clasa, tip) mai larga, care contine mai multe obiecte care au proprietati comune. De exemplu, procesorul este de o componenta electronica; monitorul este un dispozitiv de afisare, etc. Aceasta ierarhie se refera la apartenenta obiectelor la o anumita clasa (sau tip - “este de tipul…”). 
Este esential sa privim sistemele complexe din ambele perspective, studiindu-le atât din perspectiva ierarhiei structurale, deci a obiectelor care le compun, cât si a ierarhiei de tip, deci a claselor carora le apartin. La rândul lor, clasele din care fac parte obiectele pot fi organizate sau studiate ca elemente componente ale unei ierarhii, prin care o clasa este considerata ca primitiva (parinte) a unei alte clase. Cele doua tipuri de ierarhii, ierarhia de clase si ierarhia de obiecte nu sunt independente, si, împreuna, pot sa reprezinte un sistem complex. 
La fel ca oricare sistem complex, software-ul poate fi controlat prin descompunerea lui. Rolul descompunerii unui sistem în general (si al programelor în special) este de a permite întelegerea si manevrarea acestuia: sistemul este descompus în parti din ce în ce mai mici, fiecare dintre ele putând fi rafinata si dezvoltata independent. Principiul “divide-et-impera”, care se aplica în multe situatii, este util si în programare. 

Se pot identifica doua tipuri de descompunere a programelor: descompunerea algoritmica si descompunerea orientata pe obiecte. 
Descompunerea algoritmica permite abordarea structurata a programarii. Programul este împartit în module, în functie de actiunile pe care trebuie sa le efectueze, fiecare modul se împarte în elemente functionale (blocuri, proceduri, functii), într-o structurare de sus în jos (top-down), care urmareste diagrma de trecere a datelor în cursul executiei. 
Descompunerea orientata pe obiecte este o alternativa de descompunere prin care programul se descompune dupa obiectele care pot fi identificate, fiecare obiect având asociate o multime de operatii care sunt apelate în cursul desfasurarii programului. 
O problema nu poate fi abordata simultan prin ambele metode; se alege fie una, fie cealalta metoda. Care dintre ele este cea mai buna? Nu exista un raspuns absolut si universal valabil, dar experienta a dovedit ca pentru sisteme de dimensiuni mari, descompunerea orientata pe obiecte este mai eficienta, mai sigura si mai flexibila.


Limbaje ce permit programarea obiect-orientata

Primul limbaj de programare ce a fost acceptat ca limbaj OO a fost Simula(1967). Acesta a fost creat pentru a penru a rula simulari, unde cea mai importanta metoda de reprezentare a informatiei erau obiectele. Smalltalk este limbajul ce ocupa cel mai relevant loc in istoria POO, in perioada lui fiind dezvoltata cea mai mare parte a teorieri POO. In functie de gradul in care limbajele folosesc arhitectura obiect-orientata avem:


-limbaje pur OO, totul in acele limbaje fiind considerat obiect (Eiffel,Emerald,JADE,Ruby,Smalltalk,Obix,Self);
-limbaje construie in special pentru OO, caracteristici OO dar implementeaza si elemente procedurale(C#,Javam,Delphi,VB.NET, Python);
-limbaje adaptate la modelul OO, au fost initial procedurale insa le-au fost adaugate cateva functii OO, (Pascal, Visual Basic, Fortran, Perl, COBOL 2002, PHP, ABAP);
-limbaje cu suport pentru tipuri de date abstracte, insa nu implementeaza toate proprietatiile programarii obiect-orientate, numite si limbaje bazate pe obiecte (Modula-2,CLU,Plioant);


Diagrame UML

UML (Unified Modelling Language) reprezinta un limbaj vizual de modelare folositor în domeniul software, dedicat construirii sistemelor complexe si realizarii documentelor de specificaţii, facand referire in mare parte la vizualizarea, specificarea, construirea şi documentarea sistemelor de aplicaţii. Prezinta si limitări cu privire la generarea codului şi reprezinta de asemenea un mijloc bun pentru domeniul ingineriei programării.

Scopul unui limbaj de modelare este analiza si proiectarea programelor. UML reprezinta limbajul universal standard pentru dezvoltatorii software de pretutindeni, si de asemenea o combinatie excelenta a celor mai bune trei limbaje de modelare anterioare orientate pe obiecte (Booch, OMT, and OOSE). Asadar limbajul UML reuneşte cele mai bune tehnici şi practici din domeniul ingineriei programării, care şi-au dovedit eficienţa în construirea sistemelor complexe, rezultatul avand o expresivitate foarte buna care ajuta la rezolvarea diverselor probleme de modelare pe care vechile limbaje nu reuseau sa le indeplineasca foarte bine. UML ar putea indeplini pe langa rolul de limbaj vizual de modelare si cel de limbaj vizual de programare, dar momentan nu dispune de întreg sprijinul semantic şi vizual pentru a înlocui limbajele de programare

Limbajul de modelare modificat (UML - The Unified Modeling Language) consta in arhitecturi de sisteme ce functioneaza pe analiza si proiectarea obiectelor cu un limbaj corespunzator pentru specificarea, vizualizarea, construirea si documentarea artefactelor sistemelor software si de asemenea pentru modelarea în întreprinderi. UML este un limbaj de modelare care ofera o exprimare grafica a structurii si comportamentului software. Pentru aceasta exprimare grafica se utilizeaza notatiile UML.

UML este un limbaj de modelare vizual, orientat obiect, care descrie proprietăţile structurale şi dinamice ale unui sistem software. Prin sistem software se întelege o BD sau un modul de cod în general. Spre deosebire de modelul EAE, UML este o colecţie de tehnici de modelare, folosite pentru tratarea multor aspecte ale procesului de concepere şi dezvoltare a software-ului, de la proiectarea BD la interacţiunea modulelor de cod.

Fiecare tehnică de modelare de mai sus dă o vedere diferită, statică sau dinamică, a unei aplicaţii. Colecţia de vederi se numeşte model. Iată unele din tehnicile de modelare UML: diagrame de clase, sau diagrame statice de structură, care modelează entităţile unui sistem prin clase cu atribute şi comportare. Diagramele de clasă descriu, de asemenea, asocierile dintre clase şi constrângerile asupra acestora. Apoi, alte tehnici: diagrame de obiecte, diagrame de "caz de utilizare", diagrame de stare, diagrame de secvenţe, diagrame de activitate, diagrame de colaborare.

Notatiile UML constituie un element esential al limbajului pentru realizarea propriu-zisa a modelarii si anume partea reprezentarii grafice pe care se bazeaza orice limbaj de modelare. Modelarea în acest limbaj se realizeaza prin combinarea notatiilor UML în cadrul elementelor principale ale acestora denumite diagrame. În cadrul UML-ului descoperim 9 tipuri de diagrame: diagrama cazurilor de utilizare, diagrama de secventa, diagrama de colaborare, diagrama de clase (cea mai utilizata), diagrama de stari, diagrama de componente, diagrama de constructie, diagrama de obiecte, diagrama de activitati. În cele ce urmeaza vor fi prezentate notatiile UML care vor fi grupate dupa diagramele corespunzatoare fiecarei notatii în parte.

În standardul UML, versiunea 1.4 sunt definite următoarele diagrame, pe cele două categorii:



a. pentru descrierea structurală:

- Class Diagram;

- Object Diagram;

- Component Diagram;

- Deployment Diagram.

b. pentru descrierea comportamentală:

- Use Case Diagram;

- Activity Diagram;

- Statechart Diagram;

- Sequence Diagram;
Use Case Diagram
Use case diagram este un tip de diagramă din care reiese modul de utilizare a sistemului informatic - modul în care utilizatorii interacţionează cu acesta (în corespondenţă directă cu task-urile acestor utilizatori). Utilizarea use case diagram nu este absolut necesară pentru a scrie o specificaţie cu use case-uri dar este utilă pentru a crea o imagine generală asupra sistemului.
Elementele utilizate şi notaţiile lor sunt următoarele:


Element

Descriere

Notaţie

Actor

Un actor este, în principiu, un utilizator al sistemului, dar poate fi şi un alt sistem informatic care interacţionează cu sistemul analizat.




Use

Case


Use Case-urile se reprezintă sub forma unei elipse în interiorul căreia este scris numele Use Case-ului respectiv.



Asociere


Asocierea este utilizată pentru a indica legătura dintre un Actor şi un Use Case, în sensul că acel actor participă într-un fel oarecare în acel Use Case.


Un exemplu simplu de utilizare a diagramei este următorul:




Între actori şi use case-uri pot să existe relaţii de generalizare/specializare atunci când un actor sau un use case poate fi asimilat unei clase de actori, respectiv de use case-uri.


Relaţia de tip extensie între use case-uri
Relaţiile de tip extensie (şi implicit use case-urile de extensie) se folosesc atunci când se modelează un comportament opţional sau excepţional, care nu condiţionează finalitatea use case-ului de bază. De exemplu, un utilizator poate, în cazuri excepţionale, să aleagă să depună o

reclamaţie du efectuarea unei comenzi:




Relaţia de tip includere
Relaţia de tip includere se foloseşte atunci când use case-ul inclus nu este o parte esenţială a fluxului din use case-ul de bază sau este un comportament care se repetă în mai multe use case- uri. De pildă autentificarea în sistem, deşi condiţionează introducerea unei comenzi, nu este specifică introducerii comenzii şi, de asemenea, poate fi folosită în mai multe use case-uri:

Activity Diagram
Activity Diagram reprezintă o modalitate de modelare vizuală a fluxurilor. Cu ajutorul activity diagram pot fi modelate foarte bine use case-urile, dar, în aceeaşi măsură, aceste diagrame pot fi folosite pentru modelarea proceselor de business (fără legătură cu sistemul informatic). În privinţa notaţiilor, acestea sunt foarte asemănătoare cu cele din Statechart diagram deoarece activity diagram nu sunt altceva decât o variaţie a statechart diagram.
Elementele utilizate şi notaţiile lor sunt următoarele:


Element

Descriere

Notaţie

Activitate



Prin activitate vom desemna întreaga activitate modelată prin diagramă (formată dintr-o succesiune de acţiuni). Aceasta corespunde unui task de business.

-


Acţiune


Teoretic, acţiunile sunt numite activity states şi reprezintă acţiuni desfăşurate în cadrul unui task, sau, privite altfel, acţiuni ale unui obiect.





Stare iniţială



Reprezintă punctul de intrare în activitatea respectivă. Punctul iniţial este unic şi din el porneşte întotdeauna o singură tranziţie.





Stare finală



Reprezintă punctul de ieşire din activitate. Pot fi mai multe puncte de ieşire dintr-o activitate.





Tranziţie



La încheierea unei acţiuni se trece întotdeauna la o altă acţiune sau la starea finală. Tranziţia reprezintă trecerea de la o acţiune la alta.





Decizie

Printr-o decizie (sau punct de decizie) se modelează un punct din cadrul fluxului unde se face o alegere, pe o anumită ramură din flux. În acest caz tranzacţiile de ieşire trebuie să fie de tip condiţie. Aceeaşi notaţie se foloseşte şi pentru reunirea fluxurilor după o decizie precedentă (caz în care nu mai sunt necesare condiţiile).






Condiţie


(guard)

Este un tip special de tranziţie, utilizată la fiecare dintre ieşirile posibile dintr-o decizie. Se marchează ca un text pe săgeată şi arată condiţia care trebuie îndeplinită pentru a urma acel flux.






Bara de sincronizare



Este folosită pentru cazurile în care anumite acţiuni se pot desfăşura în paralel. Într-un asemenea punct poate avea loc fie separarea fluxurilor, fie reunirea lor, după o separare anterioară. Reunirea a două fluxuri înseamnă, de fapt, introducerea unei condiţii, prin care o activitate nu poate începe decât după terminarea activităţilor finale din fluxurile ce trebuie sincronizate (de aici termenul de sincronizare).







Culoar


(swimlane)

Culoarele sunt reprezentări care permit separarea activităţilor din flux după criteriul responsabilităţii realizării activităţii.







Punctele de decizie sunt puncte din fluxul de activităţi în care se face o anumită alegere între mai multe variante posibile.

Un caz simplu este ilustrat în figura de mai jos.


Trebuie observat că tranziţiile care ies dintr-un punct de decizie sunt de tip guard – au înscrisă între paranteze pătrate o condiţie.

Notaţia utilizată pentru punctul de decizie poate fi folosită şi pentru reconectarea fluxurilor

(merge point), aşa cum se poate vedea în figura de mai jos.








Acţiunile paralele (asincrone) sunt acţiuni care pot desfăşura în paralel. În viaţa reală, aceste acţiuni sunt acţiuni care nu depind una de cealaltă. Paralelizarea acţiunilor se reprezintă pe diagramă în felul următor:





Această reprezentare ne arată că acţiunile „Verificare stoc” şi „Verificare bonitate client” sunt declanşate de apariţia unei comenzi de la client şi că aceste acţiuni sunt independenta între ele (începerea uneia nu depinde de rezultatul celeilalte).
Revenirea la fluxul unic (cu acţiuni sincronizate) se face în felul următor:

Această reprezentare ne arată că livrarea la client depinde de finalizarea acţiunilor independente

"Verificare stoc" şi "Verificare bonitate client", astfel că acţiunea "Livrare la client" nu poate începe decât după finalizarea ambelor acţiuni.

Pentru a adăuga pe diagrame informaţia privind responsabilitatea executării acţiunilor se folosesc elementele denumite swimlanes (benzi de înotare), plasându-se fiecare acţiune pe "culoarul" actorului care execută acea acţiune.




Statechart Diagram
Diagramele de tip statechart sunt utilizate pentru a specifica posibilele stări prin care poate trece un obiect şi modul în care se poate trece de la o stare la alta (modelare work-flow-uri - fluxuri de lucru-, modelare fluxuri de documente, diagrame de stări).

Trecerea de la o stare la alta este determinată de tranzacţiile intermediare - acestea corespund Acţiunilor pe care le-am întâlnit la Activity Diagram (până la urmă, Statechart Diagram reprezintă un alt mod de a vedea un flux ce poate fi modelat exclusiv prin Activity Diagram, inventată pentru a exprima mai elocvent trecerile de la o stare la alta). De exemplu o comandă primită de la un client poate fi iniţial în stare de aşteptare, pentru ca un operator să verifice bonitatea clientului şi stocul şi să accepte comanda. După acceptare, se poate produce livrarea produselor comandate şi comanda trece în starea de „comandă livrată” după care urmează facturarea şi închiderea comenzii.


Elementele utilizate şi notaţiile lor sunt următoarele:


Element

Descriere

Notaţie

Stare

Indică starea în care se găseşte obiectul la un moment dat.




Stare iniţială

Reprezintă punctul de intrare sau punctul în care obiectul este iniţiat. Punctul iniţial este unic.





Stare finală

Reprezintă punctul de final când starea obiectului nu se mai modifică.




Tranziţie



Tranziţia reprezintă trecerea de la o stare la alta, provocată de apariţia unui anumit eveniment.


În afara elementelor specifice enumerate mai sus se pot folosi punctele de decizie şi acţiunile paralele (asincrone) la Activity diagram.

În figura de mai jos este exemplu de folosire a elementelor specifice statechart diagram, pentru cazul unei comenzi:


Class Diagram
Class diagram este un tip de diagramă utilizată pentru descrierea structurii statice, adică a entităţilor sau claselor existente într-un sistem. Acest tip de diagramă este utilizat cel mai adesea de către dezvoltatori pentru specificarea claselor dar poate fi foarte util şi pentru specificarea structurii unor sisteme sau subsistem dintr-un business real.

Elementele utilizate şi notaţiile lor sunt următoarele:


Element

Descriere

Notaţie

Clasă


O clasă este reprezentată printr-un dreptunghi cu trei compartimente: în cel de sus se trece numele clasei, în mijloc se trec atributele clasei iar jos se trec operaţiile specifice clasei.





Moştenire



Moştenirea este o relaţie care indică faptul că o clasă moşteneşte caracteristicile unei clase părinte. Sensul săgeţii indică sensul în care se poate spune despre clasa copil că este o<-i>, sau este de tipul<-i> clasă părinte.





Asociere


Asocierea este o relaţie generică între două clase. Aceste relaţii pot defini şi regulile numerice de asociere (unu la unu, unu la mai mulţi, mai mulţi la mai mulţi).



Dependenţă



Atunci când o clasă depinde de o altă clasă, în sensul că utilizează acea clasă ca şi atribut al său, se foloseşte relaţia de dependenţă.



Agregare


Agregarea indică o relaţie de tip întreg-parte (se poate spune despre clasa părinte că are clase de tip copil). În această relaţie, clasa copil poate exista şi fără clasa părinte.



Compoziţie



Această relaţie derivă din agregare dar se utilizează atunci când o clasă copil nu poate exista decât în cazul existenţei clasei părinte.


În reprezentarea clasei atributele şi operaţiile sunt declarate în compartimentele speciale din dreptunghi, astfel:

- atributele:

numele atributului : tipul atributului = valoare implicită

- operaţiile:

numele operaŃiei (parametri) : tipul valorii returnate


Atunci când diagrama este folosită pentru a modela structuri de business se pot folosi tipurile de date specifice business-ului, nu programării, de exemplu: minut, dată calendaristică, etc.


Moştenirea este o relaţie prin care se indică faptul că o clasă moşteneşte caracteristicile clasei părinte. În plus, clasa copil poate avea propriile caracteristici.


Asocierea arată existenţa unei relaţii între clase. În exemplul de mai jos, între Persoană şi

Autovehicul următoarea relaţie: o Persoană poate avea zero, unul sau mai multe Autovehicule.




Un tip special de asociere este indicat printr-o clasă de asociere. Altfel spus, relaţia în sine este o clasă.

În exemplul de mai jos, relaţia dintre Articol şi Lista de preţuri este de tip mai mulţi la mai mulţi: un Articol poate să apară pe mai multe Liste şi o Listă poate avea mai multe Articole. Pe Liste diferite Articolele pot avea preţuri diferite.




Dependenţa indică faptul că o clasă depinde de altă clasă, în sensul în care o funcţie oarecare depinde de un parametru al său.


Agregarea indică faptul că o clasă părinte are elemente de tipul clasei copil. În exemplul de mai jos Ţara poate avea mai multe Judeţe dar, în acelaşi timp, un Judeţ poate exista chiar şi în cazul în care clasa Ţara nu există.


Într-o relaţie de tip compoziţie clasa copil nu poate exista decât dacă există o instanţă a clasei părinte. În exemplul de mai jos instanţa clasei Comisie există atâta timp cât există instanţa clasei Examen.



Pasii dezvoltarii obiect-orientate a aplicatiilor

Un obiect conține datele și procedurile încapsulate, grupate împreună pentru a reprezenta o entitate."Interfata de obiect", arata cum obiectul poate interacționa cu datele si procedurile ce il alcatuiesc. Un program orientat-obiect este descris de interacțiunea dintre aceste obiecte. Designul orientat-obiect este disciplina de definire a obiectelor și a interacțiunilor acestora pentru a rezolva o problemă care a fost identificata și documentata în timpul de analiză a conceptelor orientate-obiect.

Ceea ce urmează este o descriere a subsetul de design orientat-obiect, care nu include abordări bazate pe prototip de obiect în cazul în care obiectele nu sunt de obicei obținute prin instantieri de clase, ci de clonare (prototip), obiecte de tip class. Designul orientat-obiect este o metodă de proiectare care cuprinde procesul de descompunere și o notație pentru reprezentând atât logic și fizic, precum și modele de stat și dinamice a sistemului în proiectare.

Intrarea pentru designul obiect-orientat este asigurata de analiza acestui concept. Se realizeaza un artefact de iesire, care nu este necesar sa fie dezvoltat pentru a servi ca intrare pentru designul obiect-orientat. Analiza designului se poate desfasura in paralel, in practica rezultatul unei activitati poate sa o “hraneasca” pe alta intr-un scurt ciclu iterative de feedback. Si analiza si designul poate fi facut pas cu pas, iar artefactele pot continuu sa creasca, in loc de sa fie dezvoltate dintr-o data.

 

Compararea dezvoltarii obiect-orientate cu dezvoltarile traditionale

Programele sunt alcatuite din module, care sunt parti dintr-un program care poate fii scris si testat separat, apoi asamblat in forma finala pentru a complete un program. In limbajele procedural(exemplu C), aceste module sunt procedure, unde o procedura este o secventa de instructiuni. In C, procedurile sunt secvente de instructiuni ca declararea, testele, buclele si chemarea altor procedure. Acele procedure care intorc variable se numesc functii.

Metoda de design utilizata in programarea procedural este numita desing de sus in jos. Aceasta inseama ca se incepe cu o problema(procedura) si apoi se imparte systematic in subproceduri. Aceasta este numita descompunere functionala, care continua pana cand o problema se poate rezolva intr-o singura procedura. Dificultatea cu acest tip de programare este intretinerea software, deoarece este anevoioasa si necesita mult timp. Cand sunt facute schimbari majore in procedura principala(main), acele schimbari se pot propaga cascadat la subproceduri.

O alternative la programarea procedural este programarea obiect-orientata. Programarea obiect-orientata incearca sa simplifice dificultatile aparute la programarea procedural. In programarea obiect orientata, principalele module intr-un program sunt clasele, nu procedurile. Aceasta simbolizare se apropie de modelul real al obiectelor din lumea reala.


Concluzii

Etapa esentiala in desfasurarea acestui proces este etapa de proiectare a sistemului, chiar daca este evident ca structura interna a acestuia este nesemnificativa pentru utilizator. S-a observat ca succesul aplicatiilor obiect-orientate depinde in principal de doua conditii:



  • Prezenta unei perspective arhitecturala legata si concreta

  • Parcurgerea unui ciclu de dezvoltare combinat iterativ si incremental coordonat

 

.  



 

Bibliografie
1. Ian Sommerville - Software Engineering

2. Grady Broch – Object Oriented Development

3. Zhiming Liu - Object-Oriented Software Development with UML

4. Proiectarea si dezvoltarea de aplicatii orientate obiect : http://www.biosfarm.ro/~dragos/papers/C++-Book/

5. Chonoles, Michael Jesse; James A. Schardt (2003). UML 2 for Dummies. Wiley Publishing



6. Martin, Robert Cecil (2003). UML for Java Programmers. Prentice Hall.

7.Introduction to Object Oriented Programming Concepts (OOP) and More by L.W.C. Nirosh



8. http://en.wikipedia.org/wiki/Object-oriented_design

Dostları ilə paylaş:
Orklarla döyüş:

Google Play'də əldə edin


Verilənlər bazası müəlliflik hüququ ilə müdafiə olunur ©muhaz.org 2017
rəhbərliyinə müraciət

    Ana səhifə