Sunteți pe pagina 1din 136

MARIUS VIRGIL OANCEA, MARIUS MIHAIL SEICEANU

INGINERIA PROGRAMRII - ndrumar de laborator

Editura Universitatii Lucian Blaga ~ Sibiu 2007 ~

INGINERIA PROGRAMRII. ndrumar de laborator

Descrierea CIP a Bibliotecii Nationale a Romaniei OANCEA, MARIUS VIRGIL Ingineria programarii : indrumar de laborator/ Oancea Marius Virgil, Seiceanu Marius Mihail. Sibiu : Editura Universitatii Lucian Blaga din Sibiu, 2007 Bibliogr. ISBN 978-973-739-448-4

I.

Seiceanu, Marius Mihail

004.42 Copyright 2007, Autorii

INGINERIA PROGRAMRII. ndrumar de laborator

INGINERIA PROGRAMRII - ndrumar de laborator CUPRINS


1 Reguli de scriere a codului....................................................................................................... 12 1.1 1.2 Importanta conventiilor de cod .................................................................................... 12 Conventii ................................................................................................................................ 12 Nume de fisiere ........................................................................................................... 12

1.2.1 1.3

Clase java ............................................................................................................................... 12 Conventii de nume .................................................................................................... 14 Alte conventii .............................................................................................................. 15

1.3.1 1.3.2 1.4 2

Exemplu ................................................................................................................................. 16

Usecase si Diagrame Usecase ................................................................................................. 19 2.1 2.2 Ce sunt Usecase-urile ........................................................................................................ 19 Exemplu Usecase ................................................................................................................ 19 Usecase : Cumpara .................................................................................................... 19 Alternativa 1 : Utilizatorul nu se poate autoriza ........................................... 20

2.2.1 2.2.2

INGINERIA PROGRAMRII. ndrumar de laborator

2.2.3

Alternativa 2 : Client care a mai cumparat (Cumparator fidel -

Cumpara) ........................................................................................................................................ 20 2.3 2.4 Cantitatea de detalii........................................................................................................... 20 Diagrame UC ......................................................................................................................... 21 Actori .............................................................................................................................. 21

2.4.1 2.5 2.6 2.7 3

Relatii intre usecase-uri ................................................................................................... 22 Cand se utilizeaza UC ........................................................................................................ 23 Exercitii .................................................................................................................................. 24

Diagrame de Clase ....................................................................................................................... 25 3.1 3.2 Importanta diagramelor de clase si definitie .......................................................... 25 Componente ......................................................................................................................... 26 Clasele si interfetele.................................................................................................. 27 Asocieri intre clase .................................................................................................... 29 Relatia is a sau generalizarea ......................................................................... 31 Atribute.......................................................................................................................... 32 Operatii .......................................................................................................................... 33 Constrangeri ................................................................................................................ 33

3.2.1 3.2.2 3.2.3 3.2.4 3.2.5 3.2.6 3.3 3.4 4

Cand se utilizeaza diagramele de clase ...................................................................... 34 Exercitii .................................................................................................................................. 35

Diagrame de interactiune ........................................................................................................ 36

INGINERIA PROGRAMRII. ndrumar de laborator

4.1 4.2

Diagramele de secventa ................................................................................................... 36 Diagrame de colaborare si contradictia static-dinamic....................................... 43 Modelul static ales ..................................................................................................... 44 Usecase sistem ............................................................................................................ 44 Noul model static reiterat dupa diagrama de colaborare....................... 47

4.2.1 4.2.2 4.2.3 4.3 5

Exercitii diagrame de interactiune .............................................................................. 49

Probleme ale modelelor statice ............................................................................................. 50 5.1 Exercitii .................................................................................................................................. 52

Model View Controller ....................................................................................................... 53 6.1 Modelul MVC standard ..................................................................................................... 53 Modelul .......................................................................................................................... 53 Vizualizarea.................................................................................................................. 53 Controlerul ................................................................................................................... 53

6.1.1 6.1.2 6.1.3 6.2 6.3 6.4

Implementarea unei aplicatii utilizand modelul MVC standard ...................... 54 Exercitii .................................................................................................................................. 56 Cateva notiuni de Java ...................................................................................................... 57 Ferestre ......................................................................................................................... 57 Interceptarea evenimentelor ................................................................................ 59 Desenarea intr-un JPanel ........................................................................................ 60

6.4.1 6.4.2 6.4.3 6.5

MVC modificat Plasarea controller-ului intre MODEL si VIEW..................... 60

INGINERIA PROGRAMRII. ndrumar de laborator

6.6 7

Exercitii .................................................................................................................................. 62

Principii de proiectare obiectuala ........................................................................................ 71 7.1 7.2 7.3 7.4 7.5 7.6 Introducere ........................................................................................................................... 71 Arhitectura si dependente .............................................................................................. 71 Simptomele designului putred ...................................................................................... 71 Schimbarea cerintelor ...................................................................................................... 72 Managementul dependentelor. ..................................................................................... 72 Principii ale proiectrii claselor.................................................................................... 72 Principiul Open Closed (OCP) ............................................................................... 72 Principiul substitutiei Liskov (LSP) .................................................................... 78 Principiul dependentei inverse (DIP) ................................................................ 83 Principiul segregarii interfetelor (ISP).............................................................. 87

7.6.1 7.6.2 7.6.3 7.6.4 7.7

Principiile arhitecturii pachetelor ............................................................................... 88 Principii de coeziune ................................................................................................ 88 Principii de cuplare ................................................................................................... 89

7.7.1 7.7.2 8

Sabloane de proiectare ............................................................................................................. 98 8.1 Cateva observatii generale legate de OOP ................................................................ 99 Caracterizarea mostenirii ....................................................................................... 99 Compunerea obiectelor ........................................................................................... 99 Delegarea ....................................................................................................................100

8.1.1 8.1.2 8.1.3

INGINERIA PROGRAMRII. ndrumar de laborator

Delegare (Delegation) .............................................................................................................102 9.1 9.2 9.3 9.4 9.5 9.6 9.7 9.8 Motivatie: .............................................................................................................................102 Aplicabilitate: .....................................................................................................................105 Structura: .............................................................................................................................105 Participanti: ........................................................................................................................106 Colaborare:..........................................................................................................................106 Consecinte: ..........................................................................................................................106 Implementare: ...................................................................................................................106 Probleme propuse:...........................................................................................................107 Factory Method......................................................................................................................108 Scopul ...............................................................................................................................108 Also Known As...............................................................................................................108 Motivarea ........................................................................................................................108 Aplicabilitatea................................................................................................................109 Structura ..........................................................................................................................109 Participani .................................................................................................................109 Consecinele ...................................................................................................................110

10

10.1 10.2 10.3 10.4 10.5 10.5.1 10.6 11

Abstract factory .....................................................................................................................112 Scop ...................................................................................................................................112 Motivarea ........................................................................................................................112

11.1 11.2

INGINERIA PROGRAMRII. ndrumar de laborator

11.3 11.4 11.5 11.5.1 11.6 11.7 12

Also Known As...............................................................................................................112 Cand se utilizeaza .........................................................................................................112 Structura ..........................................................................................................................114 Participants ................................................................................................................114 Consecinele ...................................................................................................................114 Pattern-uri nrudite .....................................................................................................115

Singleton...................................................................................................................................116 Scopul ...............................................................................................................................116 Motivarea ........................................................................................................................116 Aplicabilitatea................................................................................................................116 Structura ..........................................................................................................................116 Implementare in Java ......................................................................................................117 Problema propusa .......................................................................................................117

12.1 12.2 12.3 12.4 12.5 12.6 13

Builder.......................................................................................................................................119 Intentie (cu ce scop) ....................................................................................................119 Motivatie (de ce se foloseste) ..................................................................................119 Aplicabilitate (cand il aplicam) ...............................................................................121 Structura ..........................................................................................................................121 Participanti .....................................................................................................................122 Builder (TextConvertor) .......................................................................................122

13.1 13.2 13.3 13.4 13.5 13.5.1

INGINERIA PROGRAMRII. ndrumar de laborator

13.5.2 13.5.3 13.5.4 13.6 13.7 13.8 13.8.1 13.9 14

ConcreteBuilder (ASCII Convertor) ..................................................................122 Director (RTFReader) ............................................................................................122 Product (ASCIIText, TeXText, TextComponent) ..........................................122 Interactiune (Colaborari si colaboratori) ..........................................................122 Consecinte .......................................................................................................................123 Implementare ................................................................................................................124 Exemplu restaurant ................................................................................................124 Problema propusa .......................................................................................................130

Alte cateva sabloane ............................................................................................................132 Adapter.............................................................................................................................132 Scopul ...........................................................................................................................132 Bridge ...............................................................................................................................132 Scopul ...........................................................................................................................132 Composite .......................................................................................................................133 Structura .....................................................................................................................133 Participani .................................................................................................................134 Decorator ........................................................................................................................135 Scopul ...........................................................................................................................135 Participani .................................................................................................................135

14.1 14.1.1 14.2 14.2.1 14.3 14.3.1 14.3.2 14.4 14.4.1 14.4.2 15

Bibliografie ..............................................................................................................................136

INGINERIA PROGRAMRII. ndrumar de laborator

10

INGINERIA PROGRAMRII. ndrumar de laborator

11

GLOSAR
UML Universal Modeling Language Software aplicatie, framework sau librarie OOAD Object Oriented Analysis and Design Interfata interfata unei clase, tip; se refera la operatiile publice expuse de o clasa OCL Object Constraining Language limbaj de descriere a constringerilor

INGINERIA PROGRAMRII. ndrumar de laborator

12

1 REGULI DE SCRIERE A CODULUI


Intreaga comunitate de programatori utilizeaza un set de conventii cu privire la scrierea variabilelor, claselor, metodelor, etc. Fiecare limbaj de programare are un set propriu de astfel de conventii ce TREBUIE respectate.

1.1 IMPORTANTA CONVENTIILOR DE COD


Conventiile de scriere a codului sunt importante din nenumarate motive dar cele mai importante sunt: 80% costurile unui produs soft sunt mentenanta. Nu sunt de neglijat aceste costuri. Foarte rar mentenanta este asigurata de autorul produsului software. Programatorii trebuie sa inteleaga usor codul scris de alte persoane. Conventiile fac codul mai citibil, permitand inginerilor software sa inteleaga mai usor acest cod. In produse in care se livreaza si codul sursa, trebuie sa ne asiguram ca impachetarea modulelor se face curat ca la toate celelalte produse livrate de noi (respectand intocmai conventiile). Clientul judeca dupa ceea ce vede.

1.2 CONVENTII
1.2.1 NUME DE FISIERE
Fisierele java au extensia .java Fisierul in care se conspecteaza continutul unui director se numeste README

1.3 CLASE JAVA

INGINERIA PROGRAMRII. ndrumar de laborator

13

Nu avem voie sa depasim 2000 linii intr-un fisier. Daca ne apropiem de aceasta limita inseamna ca am incalcat unul dintre pricipiile OOP.

Cel putin clasa si metodele publice trebuie commentate (utilizand standardul javadoc - /** */)

Membrii clasei se pun in ordinea relevantei clientului clasei (public, protected, private)

Liniile de program nu depasesc 80 de caractere Cand expresiile nu intra pe o singura linie, departirea se face dupa cum urmeaza: o Rupeti dupa virgule o Rupeti inainte de un operator o In expresii complexe, nu rupeti paranteze daca este posibil

Cateva exemple:
someMethod(longExpression1, longExpression2, longExpression3, longExpression4, longExpression5);

var = someMethod1(longExpression1, someMethod2(longExpression2, longExpression3)); longName1 = longName2 * (longName3 + longName4 - longName5) + 4 * longname6; // DAAAAA

longName1 = longName2 * (longName3 + longName4 - longName5) + 4 * longname6; // NUUUU

INGINERIA PROGRAMRII. ndrumar de laborator

14

// NU if ((condition1 && condition2) || (condition3 && condition4) ||!(condition5 && condition6)) { //BAD WRAPS doSomethingAboutIt(); MISS } //MAKE THIS LINE EASY TO

// DA if ((condition1 && condition2) || (condition3


&& condition4)

||!(condition5 && condition6)) { doSomethingAboutIt(); }

Comentarii: In java exista 3 tipuri de comentarii: comentarii de linie Comentarii de bloc documentatie
/** /* mai multe linii ca */ html

// .

si comentarii de
cand se genereaza

...

comentariu */.

exportat

documentatia proiectului

1.3.1 CONVENTII DE NUME


Tip identificator pachet clase Doar litere mici
java.lang

Regula

Exemplu

Substantive in mixed case in care class StudentBun fiecare cuvand incepe cu litera mare.

interfete

Vezi clase

INGINERIA PROGRAMRII. ndrumar de laborator

15

metode

Metodele trebuie sa fie verbe in acordaCalificativ() mixed case cu prima litera mica.

variabile

Asemeni

metodelor.

Nu

se int i;

recomanda ca o variabila sa inceapa float myWidth; cu _ sau $ desi este permis. Este interzisa utilizarea variabilelor scurte exeptie facand cele consecrate (i,j,k pt intregi, c,d,e pt caractere) constante Litere mari separate prin _
static final int MIN_WIDTH = 4;

1.3.2 ALTE CONVENTII


// NU MyClass m = new MyClass(); myClass.doSomething();

Evitati acessul la metode statice printr-o instanta:

// DA MyClass.doSomething();

Structura programului sa coincida cu alinierea:

INGINERIA PROGRAMRII. ndrumar de laborator

16

if (booleanExpression) { return true; } else { return false; } // AR TREBUI SCRIS return booleanExpression; if (condition) { return x; } return y; // AR TREBUI SCRIS return (condition ? x : y);

1.4 EXEMPLU
/* * @(#)Test.java * * Copyright (c) 2007 ULBS * All rights reserved. * * This software is the confidential and proprietary information of ULBS * */ 3.82 07/02/18

package java.test;

import java.test.AnotherClass;

/**

INGINERIA PROGRAMRII. ndrumar de laborator

17

* Class description goes here. * comentariu ce apare in * docum HTML ... * * @version * @author */ public class Test extends AnotherClass { /* Aici se pune implemetarea clasei */ 3.82 18 Feb 2007 Firstname Lastname

/** var1 - comentariu ce apare in * docum HTML ... */ public static int var1;

/** * var2 documentation comentariul este * mai lung de o linie - comentariu ce apare in * docum HTML ... */ private static Object var2;

/** * ...constructor Test - comentariu ce apare in * docum HTML ... */

INGINERIA PROGRAMRII. ndrumar de laborator

18

public Blah() { // ...implementare aici... }

/** * ...method doSomething comentariu ce apare in * docum HTML ... */ public void doSomething() { // ...implementare aici... } }

INGINERIA PROGRAMRII. ndrumar de laborator

19

2 USECASE SI DIAGRAME USECASE


Oamenii folosesc exemple de interactiuni pentru a explica fenomenele. Este un mod natural de abordare a lucrurilor. Aceste scenarii in care au loc interactiuni sunt foarte rar exprimate formal (intr-un limbaj nenatural). Usecase-urile au inceput sa fie utilizate pe scara larga in anul 1992 odata cu publicarea unei carti importante in domeniu (Ivar Iacobson).

2.1 CE SUNT USECASE-URILE


Scenariile sunt secvente de pasi ce descriu interactiunea intre utilizator si sistem (de exemplu adauga in cos, alege adresa de livrare, plateste, etc). UseCase-urile sunt seturi de scenarii legate impreuna printr-un scop utilizator comun (cumparatorul vrea sa cumpere, nu este interesat exact cum). Un usecase descrie scenariul principal (cand totul merge bine) si mai multe alternative. Atat scenariul principal cat si cele alternative trebuie sa aiba un nume si o lista de pasi.

2.2 EXEMPLU USECASE


Mai jos se prezinta un exemplu de usecase ce se va folosi ca exemplu pe parcursul acestei lucrari.

2.2.1 USECASE : CUMPARA


1. Utilizatorul rasfoieste catalogul si alege produsele de cumparat 2. Utilizatorul alege checkout 3. Completeaza datele de livrare 4. Sistemul prezinta pretul total incluzand taxele de livrare

INGINERIA PROGRAMRII. ndrumar de laborator

20

5. Utilizatorul introduce nr. card 6. Sistemul autorizeaza plata 7. Sistemul confirma plata 8. Sistemul trimite email de confirmare la utilizator

2.2.2 ALTERNATIVA 1 : UTILIZATORUL NU SE POATE AUTORIZA


1. La pasul 6, sistemul nu poate autoriza plata. Sistemul permite reintroducere nr card si apoi se reincearca

2.2.3 ALTERNATIVA 2 : CLIENT CARE A MAI CUMPARAT (CUMPARATOR FIDEL CUMPARA)


3.a. Sistemul arata datele de livrare cunoscute deja 3.b. Utilizatorul poate alege modificarea acestora

2.3 CANTITATEA DE DETALII


Nu exista o regula clara in ce priveste cantitatea de detalii ce trebui scrisa intr-un usecase. In general cu cat riscul proiectului este mai mare se fac usecase-uri mai detaliate evitand astfel neintelegerile sau diferentele de interpretare intre client si furnizorul de aplicatie inca de la inceput. La un usecase se pot adauga scurte capitole care sa prezinte postconditiile si preconditiile unui acestuia. Preconditiile arata care este starea presupusa a sistemului inainte de executia usecase-ului, stare pe care usecaseul se bazeaza. Postconditiile denota starea sistemului dupa executia usecaseului. De obicei in proiecte se fac doua trei usecase-uri foarte detaliate dandu-i astfel clientului sa vada care este modul de interactiune cu sistemul. Result de usecasuri sunt descrise pe scurt si imbunatatile pe parcursul dezvoltarii.

INGINERIA PROGRAMRII. ndrumar de laborator

21

2.4 DIAGRAME UC
Diagramele usecase sunt parte a UML. Se considera ca sunt utile dar nu sunt obligatorii in dezvoltarea unui proiect.
ud: Exemplu diagrame UC

Plateste << include >> Cumpara Extension Points completeaza date livrare:location

utilizator << extend >> completare date livrare

Cumparator fidel - Cumpara

Cumparator fidel

Figura 1 - Exemplu diagrama UC

2.4.1 ACTORI
Actorul este un utilizator sau sistem extern cu un anumit rol (cumparator inregistrat, cumparator neinregistrat, cumparator premium, sistem de plata). Rol - Role in engleza - nu este cea mai fericita traducere dar este un termen acceptat in letaqratura. Acest termen a fost preluat pentru prima data dintr-o traducere din suedeza. Un actor poate juca mai multe roluri si poate executa mai multe usecase-uri. Exista doua abordari diferite : se pot identifica intai usecase-urile unui sistem (usecase centric) si apoi actorii sau invers. Din experienta am observat ca abordarea in care sunt descoperiti actorii si apoi se identifica usecase-urile lor este mai simpla (actor centric).

INGINERIA PROGRAMRII. ndrumar de laborator

22

Un actor nu trebuie sa fie neaprat uman. Un sistem poate sa fie si el actor atata timp cat face parte din lista de interactiuni.

Exista mai multe puncte de vedere in legatura cu cine sunt actorii unui sistem. Un punct de vedere este cel in care actorii sunt oamenii si sistemele externe. Altii prefera sa considere ca actori sunt initiatorii de usecase-uri. Cea mai acceptata abordare in practica si literatura este cea in care actorii sunt cei care au ceva de castigat din usecase (In usecase-ul Cumpara, actorul este utilizatorul , el este cel servit de sistem).

2.5 RELATII INTRE USECASE-URI


Exista cazuri in care un usecase (Cumpara) este foarte asemanator unui alt usecase (Cumparator fidel -Cumpara) in sensul ca un cumparator generic nu este inregistrat in sistem si unul fidel este inregistrat. Usecase-ul Cumparator fidel Cumpara extinde Cumpara (vezi 3.a si 3.b). Pentru Cumpara , 3.a si 3.b sunt puncte de extensie iar pentru Cumparator fidel Cumpara sunt extensii. Relatia intre Cumparator fidel - Cumpara si Cumpara este una de generalizare, in sensul ca prima extinde cea de-a doua. Extensia se utilizeaza in general atunci cand un usecase este similar altuia dar face ceva mai mult decat primul. Extensia este un mod bun de a captura scenariile alternative. Incluziunea se foloseste atunci cand un comportament inclus intr-un usecase dorim sa fie inclus in alt usecase si nu dorim sa repetam acea descriere de comportament. Un usecase poate avea mai multe puncte de extensie. Un usecase poate extinde alt usecase extinzand unul sau mai multe puncte de extensie. Aplicati urmatoarea regula pentru a decide intre incluziune si extensie : utilizati incluziunea cand simtiti ca va repetati in descrierile dumneavoastra

INGINERIA PROGRAMRII. ndrumar de laborator

23

utilizati extends cand doriti sa descrieti o variatie a comportamentului normal (declarand punctele de extensie in usecase-ul de baza)

Relatia de generalizare se utilizeaza atunci cand intr-un scenariu, la un anumit pas utilizatorul are mai multe optiuni de a alege. De exemplu in usecase-ul Utilizeaza Bancomat utilizatorul intr-un anumit punct poate face oricare dintre tranzactiile Retrage numerar , Interogheaza sold sau Plateste facturi . Desenarea corecta a acestui fapt se face ca in figura urmatoare :
ud: Use Case cu optiuni

Utilizare bancomat

Executa Tranzactie

Plateste Facturi

Retrage numerar

Interogheaza sold

Figura 2 - Relatia de generalizare

2.6 CAND SE UTILIZEAZA UC


Este greu de imaginat o situatie in care UC-urile sunt inutile. Ele sunt unelte esentiale in capturarea cerintelor, planificarea si controlul proiectelor iterative. Capturarea cerintelor are loc in faza de elaborare. Usecase-urile se creaza in aceasta faza dar trebuiesc intretinute in intreg procesul de dezvoltare. Este foarte important sa consideram usecase-urile ca o vedere din

INGINERIA PROGRAMRII. ndrumar de laborator

24

afara asupra acestuia deci nu se asteapta o legatura stransa intre usecase-uri si clasele din program.

2.7 EXERCITII
1. Creati UseCase-uri (fiecare usecase este un document word sau text cu un continut asemanator cu cel din capitolul 2.2.1) pentru o parte a unui sistem de evidenta a cartilor inchiriate dintr-o biblioteca. 2. Creati diagramele usecase utilizand Poseidon for UML.

INGINERIA PROGRAMRII. ndrumar de laborator

25

3 DIAGRAME DE CLASE
3.1 IMPORTANTA DIAGRAMELOR DE CLASE SI DEFINITIE
Diagramele de clase sunt elementele cele mai importante in metodele de proiectare orientate obiect. Toate metodele de proiectare OOP utilizeaza intr-un moment sau altul diagrame de clase. Diagramele de clase sunt reprezentari grafice ale stucturii statice ale programelor care ajuta la intelegerea mai usoara a acestei stucturi. Diagramele de clase descriu tipurile de obiecte care alcatuiesc un sistem si relatiile existente intre acestea.

INGINERIA PROGRAMRII. ndrumar de laborator

26

Figura 3 - Exemplu de diagrama de clase

3.2 COMPONENTE
Diagramele de clase sunt compuse din : clase (student, persoana, masina, roata) interfete relatii de asociere (o masina are patru roti) relatii de mostenire (un student este o persoana)

INGINERIA PROGRAMRII. ndrumar de laborator

27

Diagramele de clase arata si componenta claselor din punctul de vedere al operatiilor si al atributelor acestora.

3.2.1 CLASELE SI INTERFETELE


O clasa este descrisa in UML printr-un dreptunghi impartit in trei zone : - zona de nume aici se scrie numele clasei (eventual si alte informatii dupa cum se va vedea mai tarziu) - zona de atribute aici se scriu atributele clasei (variabilele membru) - zona de operatii aici se scriu opeatiile / metodele clasei

Zona de nume ( A ) Zona de atribute ( B )

Zona de operatii ( C )

Figura 4 - Reprezentarea unei clase in UML (in diagramele de clase)

Desenarea diagramelor de clase se poate aborda din trei puncte de vedere diferite : perspectiva conceptuala perspectiva de specificatii perspectiva de implementare

Perspectiva conceptuala

INGINERIA PROGRAMRII. ndrumar de laborator

28

In perspectiva conceptuala, proiectantul de software deseneaza conceptele domeniului de studiu. Chiar daca aceste concepte se refera la clasele care le implementeaza, destul de des nu se poate face o mapare unu la unu intre acestea. Acest lucru se datoreaza in special faptului ca modelul conceptual nu tine cont de detalii de implementare ale aplicatiei (e.g. de limbajul de programare ales). In perspectiva conceptuala, zona B si C pot sa lipseasca.

Specificatii In perspectiva de specificatii trebuie sa ne aplecam asupra interfetelor softwareului. Implementarea inca nu intereseaza. Toate metodele de proiectare OOAD pun mare accent pe diferenta intre interfata si implementare dar din pacate in practica cele doua concepte sunt combinate si amestecate (in majoritatea limbajelor de programare clasele sunt interfete si implementari in acelasi timp). In unele discutii vati auzi cuvantul tip referindu-se de fapt la conceptul de interfata unei clase. Un tip poate poate sa fie implemetat de mai multe clase iar o clasa poate implementa mai multe tipuri (interfete).

Implementare In perspectiva de implementare, clasele se refera la clase reale din program. Chiar daca aceasta perspectiva este cel mai des utilizata in practica, ea este mult mai putin importanta decat primele doua. Faptul ca este mai des utilizata in practica este datorita faptului ca extista unelte care genereaza cod (in limbaj de nivel inalt) din ele. Deasemenea esista posibilitatea ca din cod sa se extraga astfel de diagrame in mod automat (reverse engineering).

INGINERIA PROGRAMRII. ndrumar de laborator

29

Cunoasterea perspectivei este de o importanta cruciala in desenarea si citirea corecta a unei diagrame de clase. Toate cele trei perspective pot fi desenate utilizand limbajul UML. Chiar daca limbajul UML in sine nu are un formalism de descriere al perspectivei putem adnota clasele cu un stereotip ca <<implementation class>> sau <<interface>>. Aceste adnotari (stereotipuri) se pun in zona de nume ( A ) Reprezentarea unei clase in UML (in diagramele de clase). - vezi Figura 4 -

3.2.2 ASOCIERI INTRE CLASE


Figura 3 prezinta un exemplu de diagrama de clase corespunzator unui sistem de procesare de comenzi. Acest exemplu va fi folosit in continuarea acestui laborator pentru a evidentia anumite caracteristica ale diagramelor de clase.

Asocierile reprezinta relatiile intre instante de clase (o comanda Order este format din mai multe OrderLine).

ORDER

OrderLine

Figura 5 - Asocierea numita "este format din"

Putem sa ne imaginam ca in clasa Order este un vector (sau un Set) de OrderLine. Un OrderLine este se refera la un produs din comanda. O asociere are doua capete (roles). Fiecare capat este legat la o clasa si poate sa fie optional numit . Un astfel de nume este regasit in literatura ca role name . Fiecare capat al asocierii poate avea un ordin de multiplicitate (numit si cardinalitate). Putem face distinctie intre urmatoarele tipuri de cardinalitate :

INGINERIA PROGRAMRII. ndrumar de laborator

30

fixa o 1..1 sau 1 exact o data o 4..4 sau 4 exact de 4 ori o masina are exact patru roti o samd

variabila o 0..1 asociere optionala la capatul unde este marcat in acest fel o 0..n sau * (un Order poate avea oricate (inclusiv 0) OriderLines)

In principal, cardinalitatea defineste limita minima si maxima de asociere pentru obiectele participante. Din Figura 5 putem spune ca un OrderLine poate face parte exact dintr-un Order iar un Order este format din zero sau mai multe obiecte OrderLine. Cand ordinul de multiplicitate lipseste, se presupune ca este 1. Sagetile asocierilor reprezinta navigabilitatea. Se observa ca avem o sageata dinspre Order inspre OrderLine. Aces lucru inseamna ca in clasa Order avem un membru orderLines ce este o lista, vector sau set (sau alt tip de acest fel).
public class Order { private Set orderLines;

Figura 6 - Implementare asociere Order-OrderLine

Se diferentiaza intre urmatoarele tipuri de asocieri :

INGINERIA PROGRAMRII. ndrumar de laborator

31

asocieri generice compozitii agregari

Asocierile generice sunt asocierile discutate anterior, simbolizate printr-o linie trasata intre cele doua clase. Compozitiile sunt relatii stranse intre obiecte ce spun mai multe despre asociere si anume faptul ca Order si OrderLine au acelasi ciclu de viata. Un OrderLine nu poate exista fara un Order. Un OrderLine independent in sistem indica chiar o inconsistenta a acestuia. Compozitia se sinbolizeaza printr-un romb plin.

Figura 7 - Exemplu compozitie

Relatiile slabe dintre obiecte se simbolizeaza prin romburi goale. Aceste relatii se numesc relatii de agregare.

Figura 8 - Agregare. O Persoana poate sa existe independent de faptul ca face sau nu parte dintr-un grup

3.2.3 RELATIA IS A SAU GENERALIZAREA


Relatia de mostenire se descrie grafic printr-o linie si un triunghi indreptat inspre clasa de baza.

INGINERIA PROGRAMRII. ndrumar de laborator

32

Figura 9 - Relatia de mostenire

Aceasta relatie se traduce la nivelul limbajului java prin class Student extends Persoana.

3.2.4 ATRIBUTE
Atributele sunt foarte asemanatoare cu asocierile. Atributul name din clasa Customer indica faptul ca un client are un nume. La nivel de specificatii, acest atribut ar spune faptul ca un Customer poate sa-si spuna numele si exista o posibilitate de schimbare a acestuia. La nivel de implementare, putem spune ca esista un membru name in clasa Customer . In functie de gradul de detaliere a diagramei, un atribut poate sa descrie in diagrama: numele sau, tipul, valoarea implicita si vizibilitatea acestuia. Sintaxa UML pentru descrierea unui atribut este : VIZIBILITATE NUME : TIP = VAL_IMPLICITA

INGINERIA PROGRAMRII. ndrumar de laborator

33

Din perspectiva conceptuala nu este diferenta intre un atribut si o asociere. La nivelul specificatiei si implementarii exista diferente : diagramele nu specifica daca atributele sunt optionale sau obligatorii navigabilitatea atributelor este implicita, de la clasa la atribut semantic, legatura dintre clasa si atribut este una prin valoare nu prin referinta

3.2.5 OPERATII
Operatiile sunt procese implementate de catre clase. Operatiile corespund evident metodelor claselor. Sintaxa UML pt o operatie este: VIZIBILITATE NUME(LISTA-PARAMETRI):TIP-INTORS unde: VIZIBILITATE poate sa fie : + - public, # - protected, - - privat NUME un sir de caractere LISTA-PARAMETRI : lista de parametrii cu sintaxa ca la atribute, separati prin virgula. In fata unui parametru se poate specifica in , out , inout indicand directia de utilizare a parametrului TIP-INTORS: lista de tipuri de return separate prin virgula.

3.2.6 CONSTRANGERI
La nivelul aplicatiei exista diverse constrangeri care nu pot sa fie descrise de diagramele UML (de exemplu legatura intre doua atribute). Limbalul UML permite utilizarea tuturor mijloacelor pentru descriere constrangerilor cu singura regula ca aceste constrngeri sa fie puse intre acolade ({}). In practica se utilizeaza o engleza informala pentru imbunatatirea lizibilitatii. UML chiar pune la dispozitie un limbaj

INGINERIA PROGRAMRII. ndrumar de laborator

34

de descriere a constrangerilor (OCL) dar pentru proiecte mici si medii nu se utilizeaza in mod curent. Regulile ar trebui sa fie implementate la nivelul limbajului de programare ca asertii corespunzand astfel notiunii de invariant in Design by contract . Pe scurt Design by contract este o tehnica dezvoltata de Bertrand Mayer pentru limbajul Eiffel. In principal este vorba de o afirmatie care trebuie sa fie adevarata indiferent de context. Oricand afirmatia este falsa avem un indiciu ca avem de-a face cu o eroare in program. Programele nu trebuie sa se bazeze ca afirmatiile sunt verificate. De obicei ele se verifica doar in faza de dezvoltare nu si in faza de productie a aplicatiei. Exista pentru metode : preconditii, postconditii iar in special pentru membrii, invarianti. Preconditiile/Postconditiile indica felul in care ar trebui sa arate aplicatia (sau o parte a acesteia) ininte/dupa executia unei metode. Daca avem operatia radical , o postconditie ar putea sa fie : input = result * result. Postconditiile sunt un mod de a spune ce si nu cum se face un anumit lucru.

3.3 CAND SE UTILIZEAZA DIAGRAMELE DE CLASE


in analiza desenandu-se modelul conceptual cand se specifica modelele in implementare cand dorim sa ilustram o tehnica de implementare sau alta

In practica : nu se utilizeaza toate elementele mentionate in laborator ci doar cele care au sens intr-un context dat

INGINERIA PROGRAMRII. ndrumar de laborator

35

nu se deseneaza modelul pentru toate clasele din sistem. Totdeauna trebuie sa ne concentram pe o parte a acestuia eliminand partile neinteresante in contextul respectiv.

3.4 EXERCITII
1) Creati clasele java prezentate in modelul (diagrama de clase) din Figura 3. 2) Creati modelul conceptual pentru un program utilizat intr-o biblioteca. 3) Realizati diagrama de clase utilizand Poseidon for UML..

INGINERIA PROGRAMRII. ndrumar de laborator

36

4 DIAGRAME DE INTERACTIUNE
Diagramele de interactiune modeleaza modul in care un grup de obiecte colaboreaza pentru a realiza un deziderat comun. De obicei aceste diagrame captureaza un singur usecase. In general modelele bune se concentraza pe un singur aspect al unei probleme. Diagramele de interactiune prezinta obiecte exemplu (instante) si mesajele schimbate de acestea. Pentru a explica mai bine consideram urmatorul scenariu: comanda mai multor produse intr-un magazine virtual. STEP1 : Fereastra de introducere a comenzii trimite un mesaj pregateste la o Comanda. STEP2 : Comanda trimite mai departe aces mesaj la fiecare inregistrare din comanda (numita scurt Inregistrare) STEP3 : Fiecare Inregistrare, verifica Stoc-ul corespondent STEP4: daca Stocul este disponibil, Inregistrarea sterge cantitatea corespunzatoare din Stoc si creaza o unitate de livrare. Exista doua tipuri de diagrame de interactiune: de secventa si de colaborare.

4.1 DIAGRAMELE DE SECVENTA


In diagramele de secventa, obiectele sunt insiruite pe orizontala in niste dreptunghiuri. Pe verticala se pot vedea schimburile de mesaje in ordinea curgerii timpului.

INGINERIA PROGRAMRII. ndrumar de laborator

37

sd: Exemplu diagrama secventa

obiectul 1 :T 1) .mesaj la ora 12

obiectul 2 :

obiectul 3 :

2) .mesaj la ora 13

2) 1) raspuns

Timpul curge in jos

Figura 10 - Obiectele ce interactioneaza sunt puse pe orizontala. Pe verticala, de sus in jos este curgerea timpului. Nota: lifeline-ul obiectului 1 nu are dreptunghi. Aceasta nu este neaparat o greseala deoarece nu este evidentiat in diagrama apelul unei metode ale obiectului 1.

Liniile verticale punctate sunt numite lifelines . Sagetile reprezinta mesajele intre obiecte. Ordinea acestora este data de pozitia lor (sagetile pozitionate mai sus in lifetime reprezinta mesajele trimise mai devreme) Pe lifelines se pot observa niste dreptunghiuri care se pot interpreta ca pozitii ale apelurilor pe stiva. Un nou dreptunghi inseamna un nou apel. Aceste dreptunghiuri de activare se pot omite in unele desene (in special in cazul in care se deseneaza pe hartie) desenarea devenind astfel mai usoara dar desenul mai greu de citit si inteles motiv pentru care se recomanda desenarea acestor dreptunghiuri.

INGINERIA PROGRAMRII. ndrumar de laborator

38

sd: Sequence diagram: Comenzi

fereastraIntroducere: 1) .pregateste

oComanda:

oInregistrareComanda:

stocCorespondent:

unitateLivrare:

2) .pregateste 3) .disponibil = verifica

3) 4) .[disponibil] sterge

4) 5) .[disponibil] << create >> 5) 2) 1)

Figura 11 - Diagrama de secventa corespunzatoarea usecase-ului considerat

In figura de mai sus se observa o constructie in formatul [disponibil] sterge. Ea se poate citi ca : mesajul sterge este trimis doar daca conditia disponibil este adevarata. In pseudocod:
If (disponibil) { sterge() ; }

Constructia

3).

disponibil=verifica()

se

citeste

ca :

obiectul

oInregistrareComanda pe parcursul executarii metodei sale pregateste face un apel stocCorespondent.verifica() . Rezultatul acestui apel este introdus in variabila disponibil .

INGINERIA PROGRAMRII. ndrumar de laborator

39

oComanda trimite mesajul pregateste de mai multe ori la divese instante oInregistrareComanda Putem sa ne imaginam ca oComanda face o iteratie si cheama oInregistrareComanda.pregateste pentru fiecare inregistrare din comanda. Diagrama de mai sus nu spune nimic despre aceasta iteratie. Iteratia se poate specifica fie prin prefixarea mesajului cu * fie utilizand o notatie cadru exemplificata cateva pagini mai jos.

mesaje

Return din procedura

Dreptunghi activare

participant

lifeline

INGINERIA PROGRAMRII. ndrumar de laborator

40

Figura 12 - Explicatie elemente din diagrama

Un obiect se poate autodistruge sau poate sa distruga alt obiect.


sd: Exemplu diagrama secventa

obiectul 1 :T 1) .mesaj la ora 12

obiectul 2 :

obiectul 3 :

obiect de distrus :

2) .mesaj la ora 13 3)

3) 2) 1) raspuns 4)

4)

mesaj distrugere

Figura 13 - Obiectul 2 trimite un mesaj de distrugere obiectului de distrus. In punctul in care mesajul atinge obiectul de distrus "lifeline" ul acestuia nu mai continua si se termina cu un "X".

Modelele trebuie sa prezinte doar ceea ce este relevant. O problema comuna a acestor diagrame este modul de desenare a iteratiilor dupa cum s-a mai amintit si mai sus. Diagramele de secventa ca si usecase-urile nu sunt facute pentru acest lucru. Pentru a desena structuri de control se recomanda diagramele de activitati sau codul insusi. Diagramele de secventa trebuie tratate ca o

INGINERIA PROGRAMRII. ndrumar de laborator

41

explicatie a modului in care obiectele interactioneaza nu un mod de descriere a unui algoritm. Iteratiile si conditiile se pot reprezenta in diagramele de secvente utilizand cadre de interactiuni . Un cadru de interactiune este o zona marcata corespunzator intr-o diagrama de secventa.
sd: Sequence diagram: Blocuri de control

oComanda :

oInregistrare :

loop(1,100) [] 1) .pregateste

1)

Figura 14 - Dreptunghiul (cadrul) loop se citeste ca: oComanda cheama metoda pregateste pentru fiecare inregistrare (minim 1, maxim 100)

In acelasi mod se pot desena si conditiile.

INGINERIA PROGRAMRII. ndrumar de laborator

42

sd: Sequence diagram: Blocuri de control

oComanda :

oInregistrare :

stocCorespondent :

oUnitateLivrare :

loop() [pentru fiecare inregistrare din comanda ] 1) .pregateste 2) .disponibil = verifica

2) alt [disponibil ] 3) .sterge

3) 4) << create >> 4)

[! disponibil ]

1)

Figura 15 - O parte din diagrama initiala dar corectata cu loop si alt

Cadrele alt au de obicei mai multe zone, fiecare zona fiind gardata cu o expresie (conditie). Cadrul loop are o singura regiune, expresia de garda fiind chiar o reprezentare a ce se itereaza. Mai jos se prezinta lista tuturor tipurilor de cadre si intelesul acestora : alt mai multe alternative (ca switch) opt regiune ce se executa doar daca conditia este adevarata (echivalent IF) par fragmentele ruleaza in paralel loop fragmentul se executa de mai multe ori

INGINERIA PROGRAMRII. ndrumar de laborator

43

region fragmentul reprezinta o sectiune critica (doar un fir are acces in regiune la un moment dat)

neg fragmentul contine interactiuni invalide ref refera o interactiune din alta diagrama sd utilizata pentru a marca o intreaga diagrama de secventa

Mesajele transmise pot avea si parametri. In unele cazuri dorim sa trasmite un mesaj fara a tranfera controlul nemaifind vorba despre apeluri de proceduri ci crearea de noi fire sau comunicare prin sisteme de mesagerie. Se folosesc sagetile corespunzatoare mesajelor asincrone. Pe hartie se sugereaza utilizarea unei jumatati se sageata cum se poate vedea mai jos.

Figura 16 - Mesaj asincron

Diagramele de secvente sunt utilizate cand se descrie comportamentul mai multor obiecte in acelasi usecase. Cand se doreste descrierea comportamentului unui singur obiect acoperind comportamentul din mai multe usecase-uri se foloseste o diagrama de stare State diagram .

4.2 DIAGRAME DE COLABORARE SI CONTRADICTIA STATIC-DINAMIC


A doua forma de diagrame de interactiune sunt diagramele de colaborare. Aici obiectele implicate in interactiune sunt desenate ca mici icoane legate intre ele prin mesaje numerotate. Prin numerotarea mesajelor secventialitatea isi pierde oarecum din evidenta dar plasarea spatiala a micilor icoane reprezentand obiectele ce

INGINERIA PROGRAMRII. ndrumar de laborator

44

interactioneaza le poate plasa in pachete sau poate evoca alte trasaturi ale acestora. Ca si scop, in timp ce diagramele de secventa isi propun sa arate ordinea temporala a mesajelor, cele de colaborare arata relatia structurala intre obiectele ce colaboreaza.

4.2.1 MODELUL STATIC ALES


cd: Telefon

CellularRadio

Display

Microphone

Telephone

Button

Speaker

Dialer

Figura 17 - Model static telefon

Pentru a intelege mai bine o sa incercam sa modelam modul in care un utilizator de telefonie mobila da un telefon. Prin intelegerea fenomenului putem descrie scenariul prezentat mai jos.

4.2.2 USECASE SISTEM

INGINERIA PROGRAMRII. ndrumar de laborator

45

Usecase : Da un telefon (versiunea 1) 1. Utilizatorul apasa butoanele pentru a forma numarul 2. Utilizatorul apasa butonul verde Send 3. Se stabileste conexiunea cu reteaua 4. Se stabileste conexiunea cu interlocutorul Prima versiune de usecase este doar o versiune de inceput ce ignora multe detalii necesare realizarii unui astfel de sistem. Spre exemplu, nu se specifica faptul ca la apasarea butoanelor se aude un mic ton si se actualizeaza ecranul telefonului. Este necesara asadar elaborarea unei noi versiuni imbunatatite. Usecase : Da un telefon (versiunea 2) 1. Utilizatorul apasa butoanele pentru a forma numarul 2. La fiecare digit apasat, ecranul se actualizeaza si digital de adauga la numarul de telefon de format 3. La fiecare digit apasat se genereaza tonul corespondent ce se emite in difuzor 4. Utilizatorul apasa butonul verde Send 5. Indicatorul in use se aprinde pe ecran 6. Se stabileste conexiunea cu reteaua 7. Digitii acumulati se trimit retelei 8. Se stabileste conexiunea cu interlocutorul Chiar daca si aceasta versiune este simplista ea serveste scopului nostru cu succes. Usecase-ul de mai sus expliciteaza destul de clar procedura de telefonare. Ceea ce nu este evident este cum vor interactiona obiectele din modelul static (din diagrame de

INGINERIA PROGRAMRII. ndrumar de laborator

46

clase) in cadrul acestei proceduri. Putem sa ne imaginam urmatoarele : obiectul Button emite un mesaj Digit la Dialer. Dialer-ul cere obiectului Display sa afiseze digitul si cere difuzorului (Speaker) sa emita tonul corespunzator. Digitii apasati se acumuleaza intr-o lista ce formeaza numarul de telefon. Cand se apasa butonul Send obiectul Button trimite mesajul Send la Dialer. Dialer trimite un mesaj de conectare connect la sistemul celular (trimitand si numarul de telefon din lista acumulata). Acesta din urma cere obiectului Display sa lumineze indicatorul in use .
cld: Collaboration diagram: Telefoneaza

:Speaker

1.2 : EmitTone(code)

1* : Digit(code) :Button :Dialer

2.1 : Connect(pno) :CellularRadio

2 : Send 1.1 : DisplayDigit(code)

Send :Button

:Display 2.1.1 : InUse

Figura 18 - Diagrama Colaborare pentru telefonare

De mentionat : Dreptungiurile din aceste diagrama reprezinta obiecte NU clase. Nu este corect sa cream o asociere intre doua obiecte in aceste diagrame daca nu exista una corespunzatoare in diagrama de clase (liniile conectoare din diagramele de colabore sunt instante ale asocierilor din diagrama de clase).

INGINERIA PROGRAMRII. ndrumar de laborator

47

Se observa ca obiectele si mesajele utilizate in diagrama de colaborare sunt altele decat ceea ce s-a prezentat in modelul static. S-a incalcat chiar ultima regula mentionata mai sus. Avem legaturi care nu reflecta asocieri din structura statica. Problema poate sa fie faptul ca modelul nostru dinamic (Figura 18 - Diagrama Colaborare pentru telefonare) este incorect. Ar trebui sa fortam modelul dinamic sa respecte modelul static dar cum ar arata noul model dinamic ? Noul model dinamic ar avea un element central Telefon care va receptiona mesaje de peste tot pe care le va transfora in mesaje trimise de catre el la componenta respectiva. Un astfel de sistem este deosebit de cuplat. Telefon ar fi un controler principal care va trebui sa stie cate ceva despre toate obiectele din jurul lui si toate ar trebui sa stie despre el. Intreaga inteligenta a sistemului este plasata in acest obiect. Astefel de obiecte principale devin puternic interconectate ducand la o rezistenta sporita la modificari (cand se schimba o componenta a sistemului este posibil ca toate celelalte sa trebuiasca modificate). Un model ca in Figura 18 este cel corect din punct de vedere OOP, responsabilitatile obiectelor sunt puternic separate, fiecare obiect avand cate putina inteligenta si nu exista un obiect special atotstiutor. Astgel de modele duc la cuplaje reduse si implicit la sisteme modificabile. Totusi spuneam ca nu respectam diagrama de clase (modelul static). Nu ramane de facut decat sa-l schimbam pe acesta. Noul model facut conform cu modelul dinamic este prezentat mai jos.

4.2.3 NOUL MODEL STATIC REITERAT DUPA DIAGRAMA DE COLABORARE

INGINERIA PROGRAMRII. ndrumar de laborator

48

cd: Telefon v2

Display

+displayDigit (code :int):void +inUse():void

Speaker

Dialer

CellularRadio

+emitTone (code :int):void

+digit(code :int):void +send ():void

+connect (number :PNO):void

Button

Figura 19 - Noul model static pentru Telefon. De aceasta data respecta modelul dinamic

De aceasta data se observa ca s-au adaugat si ceva operatii in clasele modelului static. Acest lucru a fost posibil datorita faptului ca modelul dinamic a cerut aceste metode. Noul model ar putea parea inconfortabil pentru ca nu arata intocmai un telefon asa cum el este in lumea reala clasa Telephone a disparut clasa Microphone a disparut

INGINERIA PROGRAMRII. ndrumar de laborator

49

am pierdut din vedere ca un telefon este compus din butoane si display.

Toate cele mentionate mai sus sunt bazate pe structura fizica a telefonului si nu are nici o legatura cu comportamentul acestuia. Noul model se bazeaza pe comportamentul real al telefonului. Clasele disparute nu sunt o problema deoarece ele nu au nici un sens din moment ce nu sunt prinse in niciun comportament descris. (este posibil ca ele sa reapara in alt usecase, caz in care vor fi reinserate)

4.3 EXERCITII DIAGRAME DE INTERACTIUNE


1. Intr-un program de zaruri se considera usecase-ul arunca zaruri descris in continuare : se arunca primul zar si se citeste valoarea, se arunca al doilea zar si se citeste valoarea. Ilustrati acest usecase printr-o diagrama de secventa. 2. Creati o diagrama de secventa care sa exprime faptul ca un bucatar poate sa incalzeasca in acelasi timp o chifla si un hamburger. 3. Utilizand Poseidon for UML., desenati toate diagramele de colaborare din capitolul 4.1.

INGINERIA PROGRAMRII. ndrumar de laborator

50

5 PROBLEME ALE MODELELOR STATICE


Pe parcursul acestui laborator vom face referire la modelul static prezentat in capitolul 4.2 - Diagrame de colaborare si contradictia static-dinamic. O prima problema a celui de-al doilea model prezentat este in jurul clasei Button. De ce clasa buton trebuie sa aiba cunostinta de clasa Dialer ? Nu ar fi mai bine ca Button sa fie o clasa reutilizabila si an alte zone ale sistemului sau in alte programe care nu au Dialer-i? Din pacate, fiind interconectata cu Dialer, acest lucru nu este posibil. Din fericire exista un mod elegant de a realiza acest lucru. Dependentele de acest gen pot sa fie sterse destul de usor.
cd: Telefon v3 - Deconectare Button Dialer

Button

+doSomething ():void

DigitButton

SendButton

Dialer

INGINERIA PROGRAMRII. ndrumar de laborator

51

Figura 20 - Legatura dintre Button si Dialer a fost stersa

Ideea este de a avea o clasa generala Button care nu stie sa faca nimic altceva decat sa cheme propria metoda doSomething . O clasa particulara (SendButton) strans legata de Dialer, implementeaza acea metoda. Intreaga interactiune (mouse, tastatura, apasare buton) este incapsulata in clasa generica Button. Din exterior clasa Button ofera doar o metoda care se poate rescrie. Tot un exemplu de cuplaj este clasa Display. De aceasta data problema este diferita dar solutia este asemanatoare. Nu se pune problema reutilizarii clasei Diplay fiind o clasa particulara acestui sistem dar exista posibilitatea ca la un moment dat telefonul sa fie produs cu un alt display decat cel proiectat initial. In acest caz ar trebui sa avem la fel ca mai sus, sistemele dependente de AbstractDisplay iar Display sa implenteze interfata respectiva. O a treia problema a clasei Display este faptul ca ea are doua responsabilitati diferite : sa afiseze digitul apasat sa afiseze mesaje in use

Clasa CellularRadio este interesata de Display doar din puncul de vedere al mesajului InUse. Dialler-ul este interesat de Display numai din punctul de vedere al metodei de afisare a digitului. Daca cele doua puncte de vedere sunt strans legate este posibil ca la o modificare a clasei Display venita ca o cerinta a clasei Dialer sa fie afectata si clasa CellularRadio. Un astfel de lucru este de nedorit si poate sa fie evitat prin segregarea interfetelor.

INGINERIA PROGRAMRII. ndrumar de laborator

52

cd: Telefon v4 Segregare

Dialer

CellularRadio

DialerDisplay

CRDisplay

+displayDigit():void

+inUse():void

Display

Figura 21 - Dialer si CellularRadio depinde doar de o mica parte a clasei Diplay

In afara acestor probleme prezentate aici se vor prezenta si alte probleme pe parcursul laboratoarelor urmatoare.

5.1 EXERCITII
1. Creati modelul de clase actualizat cu cele doua modificari 2. Creati noua diagrama de colaborare conforma cu noul model in care sau operat modificarile din acest laborator

INGINERIA PROGRAMRII. ndrumar de laborator

53

6 MODEL VIEW CONTROLLER


MVC este un mod de a divide funcionalitatea claselor implicate in mentenana si vizualizarea datelor avnd ca scop minimizarea gradului de cuplare intre aceste obiecte. Arhitectura MVC a luat natere pentru a mapa taskurile tradiionale: intrare, procesare si ieire, pe interaciune cu utilizatorul in mod grafic. Aceasta arhitectura are trei componente (model, vizualizare si controler) ce vor fi explicate mai jos.

6.1 MODELUL MVC STANDARD


6.1.1 MODELUL
In arhitectura MVC, modelul reprezint datele aplicaiei mpreuna cu regulile ce guverneaz accesul/modificarea acestor date. Modelul anuna vizualizrile cnd el s-a schimbat si ofer vizualizrii informaii despre starea sa. De asemenea, ofera controlerului posibilitatea de a accesa functionalitati ale aplicatiei incapsulate in model.

6.1.2 VIZUALIZAREA
Vizualizarea afiseaza continutul modelului. El acceseaza date din model si specifica cum se vor prezenta utilizatorului aceste date. Cand modelul se schimba, este responsabilitatea vizualizarii sa mentina consistenta prezentarii. Vizualizarea inainteaza gesturile utilizatorului controlerului.

6.1.3 CONTROLERUL
Controlerul defineste comportamentul aplicatiei; interpreteaza gesturile utilizatorului si le transforma in actiuni asupra modelului. Intr-o aplicatie GUI standalone, gesturile utilizatorului pot fi clickurile de butoane sau selectii in meniuri. Intro aplicatie WEB, aceste gesturi apar ca cereri http GET sau POST la nivelul Web (Web tier).

INGINERIA PROGRAMRII. ndrumar de laborator

54

In figura urmatoare se pot regasi cele explicate mai sus. Liniile intrerupte sunt evenimente iar cele pline sunt invocari de metode. In dreptunghiuri s-au scris responsabilitatiile claselor cu rolul respectiv.

Figura 22 MVC standard

6.2 IMPLEMENTAREA UNEI APLICATII UTILIZAND MODELUL MVC STANDARD


Presupunand ca cele trei obiecte MODEL, VIEW si CONTROLLER sunt instantiate, se vor intampla urmatoarele lucruri: 1) VIEW ul se inregistreaza ca listener la MODEL. Orice modificare a valorilor ce compun modelul va rezulta intr-un eveniment difuzat. MODEL-ului nu-i pasa nici de VIEW nici de CONTROLLER, el doar difuzeaza evenimentul la toti listenerii, oricare ar fi acestia. 2) CONTROLLER-ul este legat de VIEW. Orice actiune a utilizatorului asupra VIEW-unui va rezulta in apelul unui listener specific din CONTROLLER.

INGINERIA PROGRAMRII. ndrumar de laborator

55

3) CONTROLLER-ul pastreaza o referinta inspre MODEL. Atunci cand un utilizator actioneaza asupra VIEW-ului, au loc urmatoarele: 1) VIEW-ul simte ca are loc o actiune (de exemplu, are loc apasare unui buton sau mutarea unui scrollbar) utilizand un listener inregistrat pentru acel eveniment specific. 2) VIEW-ul invoca metoda aleasa din CONTROLLER 3) CONTROLLER-ul acceseaza modelul eventual modificandu-l in concordant cu actiunea utilizatorului 4) MODEL-ul notifica listenerii interesati despre schimbare (de exemplu VIEWul). In unele arhitecturi este posibil ca CONTROLLER-ul sa fie responsabil si cu actualizarea VIEW-ului (des utilizat in arhitectura J2EE)

INGINERIA PROGRAMRII. ndrumar de laborator

56

Figura 23 Interactiunea dintre model view si controller in aplicatia standard aleasa

6.3 EXERCITII
1) Trasati diagrama de clase pentru exemplul de mai sus 2) Trasati diagrama de colaborare si actualizati diagrama de clase daca este necesar 3) Realizati un program pe arhitectura MVC care sa realizeze o fereastra in care sa fie trei controale JTextField (XPosition, YPosition, Radius) JTextField si un JPanel in care o sa fie pus un cerc la coordonatele date de XPosition si YPosition, de raza Radius. Utilizatorul va putea influenta modelul prin modificarea valorilor din JTextField-uri. Atentie !!! Modelul NU trebuie sa pastreze vreo referinta catre VIEW. Pt cateva consideratii Java-Interfata vezi urmatoarea sectiune.

INGINERIA PROGRAMRII. ndrumar de laborator

57

4) Inlocuiti controalele JTextField cu JSlider 5) Adaugati in interfata un buton VIEW2X care deschide o fereastra noua in care se poate vedea cercul pozitionat intr-un panel de doua ori mai mare decat primul. Modificarea campurilor XPosition, YPosition si Radius va actualize ambele VIEW-uri.

6.4 CATEVA NOTIUNI DE JAVA


In aceasta sectiune se vor arata cateva notiuni generale despre limbajul java.

6.4.1 FERESTRE
Pentru a crea o fereastra se foloseste clasa JFrame. Zona pe care se pun componentele se obtine prin apelul frame.getContentPane(). Mai jos oferim un exemplu de cod ce va deschide o fereastra si va pune un buton pe aceasta.
JFrame f = new JFrame(Titlul Ferestrei); f.getContentPane().add(new JButton(Test)); f.setSize(320,200); f.setVisible();

Adaugarea componentelor se poate face la coordinate fixe sau putem lasa java sa le aranjeze dinamic dupa reguli stabilite de noi astfel ca la redimensionarea ferestrei acestea sa fie plasate automat in pozitii optime. Sectiunea de cod de mai jos, adauga un buton intr-o fereastra, la coordinate fixe:
JFrame f = new JFrame(Titlul Ferestrei); JButton b = new JButton(Test); f.getContentPane().setLayout(null); f.getContentPane().add(b); b.setBounds(10 /* X */,40 /* Y */, 50 /* latime */, 20 /* inaltime */);

INGINERIA PROGRAMRII. ndrumar de laborator

58

f.setSize(320,200); f.setVisible();

Layout-ul null se poate folosi in special in ferestre ce nu se pot redimensiona. Pentru celelalte cazuri se recomanda utilizarea unui layout existent sau construirea unui nou layout (pentru programatorii experimentati). Cele mai des utilizate layout-uri sunt: BorderLayout, FlowLayout, GridLayout, GridBagLayout. 6.4.1.1 BorderLayout, FlowLayout Prin utilizarea acestui mod de aranjare se pot aranja maxim cinci component pe un
JPanel (una la nord, una la sud, una la est, una la vest si una in centru).

Chiar daca un layout ce permite adaugarea a doar cinci component pare foarte limitat, acesta este cel mai utilizat deoarece spre exemplu componenta plasat la nord poate sa fie un panel cu mai multe component plasate in el.
JPanel panelNorth = new JPanel(); // panoul Nordic va avea doua butoane pe el plasate unul dupa altul panelNorth.setLayout(new FlowLayout()); panelNorth.add(new JButton(buton 1)); panelNorth.add(new JButton(buton 2)); // in fereastra, panoul Nordic este plasat la nord frame.getContentPane().setLayout(new BorderLayout()); frame.getContentPane().add(panelNorth, BorderLayout.NORTH); // in centru se plaseaza un JTextArea frame.getContentPane().add(new JTextArea(), BorderLayout.CENTER);

6.4.1.2 GridLayout Utilizand GridLayout componentele sunt aranjate intr-o tabela secvential incepand din coltul stanga sus. De exemplu:

INGINERIA PROGRAMRII. ndrumar de laborator

59

JPanel p = new JPanel(); p.setLayout(new GridLayout(3,2)); p.add(new JLabel(label 1)); p.add(new JLabel(label 2)); p.add(new JButton(Buton 1)); p.add(new JLabel(label 4));

va avea ca effect o plasare a celor patru component ca mai jos: Label1 Label2 Button1 Label4

6.4.2 INTERCEPTAREA EVENIMENTELOR


In general in Java putem sa ascultam modificarea starii unor component prin inregistrarea unor Listeneri la acestea. Daca dorim sa fie chemata metoda apasat() in momentul in care un buton se apasa putem utilize un ActionListener.
buton.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent ae) { apasat(); } });

De remarcat ca in java apparent se poate construe o instanta de interfata (ActionListener este o interfata nu o clasa). De fapt nu se construieste o interfata ci se creaza o instant a unei clase interne (in care actionPerformed nu mai este abstract).

INGINERIA PROGRAMRII. ndrumar de laborator

60

Daca dorim sa fim anuntati cand un JTextField este modificat putem sa inregistram un listener la documentul (modelul componentei JTextField in concordant cu MVC) acestuia:
textField.getDocument().addDocumentListener().

6.4.3 DESENAREA INTR-UN JPANEL


In multe aplicatii, componentele Java existente nu sunt suficiente si trebuie sa apelam la crearea propriilor componente. Daca dorim ca o componenta sa-si controleze modul in care ea este desenata putem sa extindem JPanel in noua componenta si sa suprascriem metoda paint. Paint este chemata automat de catre system de cate ori este necesar. Aceasta metoda primeste un obiect Graphics pe care se poate desena cu metodele draw .

6.5 MVC MODIFICAT PLASAREA CONTROLLER-ULUI INTRE MODEL SI VIEW


Chiar daca MVC standard asigura o izolare foarte buna intre cele trei componente ale programului o implementare recenta a MVC (vezi apache cocoa) modifica aceasta structura plasand CONTROLLER-ul intre MODEL si VIEW.

INGINERIA PROGRAMRII. ndrumar de laborator

61

Figura 24 Noul MVC plaseaza CONTROLLER-ul in mijloc, intre MODEL si VIEW

In acest design, VIEW-ul nu se inregistreaza direct la model ca in MVC standard ci prin intermediul CONTROLLER-ului. Din acest motiv, CONTROLLER-ul mediaza curgerea de informatii de la MODEL la VIEW (in ambele directii). Cand cele trei component sunt instantiate, CONTROLLER-ul se inregistraza ca listener la VIEW si MODEL. Cand utilizatorul interactiuneaza cu VIEW-ul: 1) VIEW-ul simte ca are loc o actiune (de exemplu, are loc apasare unui buton sau mutarea unui scrollbar) utilizand un listener inregistrat pentru acel eveniment specific. 2) VIEW-ul invoca metoda aleasa din CONTROLLER 3) CONTROLLER-ul acceseaza modelul eventual modificandu-l in concordanta cu actiunea utilizatorului

INGINERIA PROGRAMRII. ndrumar de laborator

62

4) MODEL-ul notifica listenerii interesati despre schimbare (CONTROLLER-ul in acest caz) Avantajul major al acestei tehnici este posibilitatea de decuplare completa a MODEL-ului de VIEW. CONTROLLER-ul poate dicta proprietatile ce il intereseaza din unu sau mai multe modele. Deasemenea, CONTROLLER-ul poate oferi metodele de modificare a acestor proprietati mai multor VIEW-uri .

6.6 EXERCITII
1) Creati o clasa AbstractModel
public abstract class AbstractModel { protected PropertyChangeSupport propertyChangeSupport; public AbstractModel() { propertyChangeSupport = new PropertyChangeSupport(this); } public void addPropertyChangeListener(PropertyChangeListener listener) { propertyChangeSupport.addPropertyChangeListener(listener); } public void removePropertyChangeListener(PropertyChangeListener listener) { propertyChangeSupport.removePropertyChangeListener(listener); } protected void firePropertyChange(String propertyName, Object Object newValue) { propertyChangeSupport.firePropertyChange(propertyName, newValue); } } oldValue, oldValue,

2) Extindeti aceasta clasa intr-o noua clasa TextElementModel avand urmatorii membri:

INGINERIA PROGRAMRII. ndrumar de laborator

63

private String text; private private private private private Font font; Integer x; Integer y; Integer opacity; Integer rotation;

3) Puneti la dispozitie mijloace de initializare, set, get pentru acesti membrii 4) Creati un controller abstract ca in secventa de mai jos:

INGINERIA PROGRAMRII. ndrumar de laborator

64

public abstract class AbstractController implements PropertyChangeListener { private ArrayList registeredViews; private ArrayList registeredModels; public AbstractController() { registeredViews = new ArrayList(); registeredModels = new ArrayList(); } public void addModel(AbstractModel model) { registeredModels.add(model); model.addPropertyChangeListener(this); } public void removeModel(AbstractModel model) { registeredModels.remove(model); model.removePropertyChangeListener(this); } public void addView(AbstractViewPanel view) { registeredViews.add(view); } public void removeView(AbstractViewPanel view) { registeredViews.remove(view); } // Use this to observe property changes from registered models // and propagate them on to all the views. public void propertyChange(PropertyChangeEvent evt) { for (AbstractViewPanel view: registeredViews) { view.modelPropertyChange(evt); } } /** * This is a convenience method that subclasses can call upon * to fire property changes back to the models. This method * uses reflection to inspect each of the model classes * to determine whether it is the owner of the property * in question. If it isn't, a NoSuchMethodException is thrown, * which the method ignores. * * @param propertyName = The name of the property. * @param newValue = An object that represents the new value * of the property. */ protected void setModelProperty(String propertyName, Object newValue) { for (AbstractModel model: registeredModels) { try { Method method = model.getClass(). getMethod("set"+propertyName, new Class[] { newValue.getClass() } ); method.invoke(model, newValue); } catch (Exception ex) { // Handle exception. } } } }

INGINERIA PROGRAMRII. ndrumar de laborator

65

5) In AbstractController se pastreaza doi vectori: unul reprezinta lista de obiecte MODEL inregistrate, iar unul lista de obiecte VIEW inregistrate. Cand un nou MODEL se inregistreaza, CONTROLLER-ul se inregistreaza si el ca un listener la model. Construiti un DefaultController (extensie a celui abstract) si completati partile omise.
public class DefaultController extends AbstractController { public public public public public public // static static static static static static final final final final final final String String String String String String ELEMENT_TEXT_PROPERTY = "Text"; ELEMENT_FONT_PROPERTY = "Font"; ELEMENT_X_PROPERTY = "X"; ELEMENT_Y_PROPERTY = "Y"; ELEMENT_OPACITY_PROPERTY = "Opacity"; ELEMENT_ROTATION_PROPERTY = "Rotation";

Completati partile omise aici

public void changeElementText(String newText) { setModelProperty(ELEMENT_TEXT_PROPERTY, newText); } public void changeElementFont(Font newFont) { setModelProperty(ELEMENT_FONT_PROPERTY, newFont); } public void changeElementXPosition(int newX) { setModelProperty(ELEMENT_X_PROPERTY, newX); } public void changeElementYPosition(int newY) { setModelProperty(ELEMENT_Y_PROPERTY, newY); } public void changeElementOpacity(int newOpacity) { setModelProperty(ELEMENT_OPACITY_PROPERTY, newOpacity); } public void changeElementRotation(int newRotation) { setModelProperty(ELEMENT_ROTATION_PROPERTY, newRotation); } }

6) Construiti doua VIEW-uri: unul editor al proprietatilor din model (PropertyEditorPanel) si un VIEW grafic. Ambele VIEW-uri vor fi extensii ale lui JPanel inserate intr-un JFrame respectiv intr-un JDialog. Dialogul va

INGINERIA PROGRAMRII. ndrumar de laborator

66

permite utilizatorului sa actualizeze valorile din model. Panel-ul din Frame va permite vizualizarea grafica a textului asa cum va arata acesta la momentul respectiv. Constructorul clasei PropertyEditorPanel si a metodei localInitialization:
public PropertiesViewPanel(DefaultController controller) { this.controller = controller; initComponents(); localInitialization(); } public void localInitialization() { opacitySpinner.setModel(new SpinnerNumberModel(100, 0, 100, 1)); opacitySlider.setModel(new DefaultBoundedRangeModel(100, 0, 0, 100)); rotationSpinner.setModel(new SpinnerNumberModel(0, -180, 180, 1)); rotationSlider.setModel(new DefaultBoundedRangeModel(0, 0, -180, 180)); text.getDocument().addDocumentListener(new DocumentListener() { public void insertUpdate(DocumentEvent e) { textDocumentChanged(e); } public void removeUpdate(DocumentEvent e) { textDocumentChanged(e); } public void changedUpdate(DocumentEvent e) { textDocumentChanged(e); } }); }

7) Sectiunea de cod de mai jos este chemata de catre CONTROLLER de fiecare data cand MODEL-ul raporteaza ca a fost modificat.

INGINERIA PROGRAMRII. ndrumar de laborator

67

public void modelPropertyChange(final PropertyChangeEvent evt) {

if (evt.getPropertyName().equals( DefaultController.ELEMENT_X_PROPERTY)) { String newStringValue = evt.getNewValue().toString(); xPositionTextField.setText(newStringValue); } else if (evt.getPropertyName().equals( DefaultController.ELEMENT_Y_PROPERTY)) { String newStringValue = evt.getNewValue().toString(); yPositionTextField.setText(newStringValue); } else if (evt.getPropertyName().equals( DefaultController.ELEMENT_OPACITY_PROPERTY)) { int newIntegerValue = (Integer)evt.getNewValue(); opacitySpinner.setValue(newIntegerValue); opacitySlider.setValue(newIntegerValue); } else if (evt.getPropertyName().equals( DefaultController.ELEMENT_ROTATION_PROPERTY)) { int newIntegerValue = (Integer)evt.getNewValue(); rotationSpinner.setValue(newIntegerValue); rotationSlider.setValue(newIntegerValue); } else if (evt.getPropertyName().equals( DefaultController.ELEMENT_TEXT_PROPERTY)) { String newStringValue = evt.getNewValue().toString(); text.setText(newStringValue); } else if (evt.getPropertyName().equals( DefaultController.ELEMENT_FONT_PROPERTY)) { Font f = (Font)evt.getNewValue(); String fontString = f.getFontName() + " " + f.getSize(); font.setText(fontString); currentFont = f; } // } Remainder of the code omitted

8) Cand se transmit evenimente GUI, se vor chema listeneri din codul urmator:

INGINERIA PROGRAMRII. ndrumar de laborator

68

private void yPositionTextFieldFocusLost(java.awt.event.FocusEvent evt) { try { controller.changeElementYPosition( Integer.parseInt(yPositionTextField.getText())); } catch (Exception e) { // Handle exception. } } private void yPositionTextFieldActionPerformed(java.awt.event.ActionEvent evt) { try { controller.changeElementYPosition( Integer.parseInt(yPositionTextField.getText())); } catch (Exception e) { // Handle exception. } } // // { JFontChooserDialog fontChooser = new JFontChooserDialog((Dialog)this.getTopLevelAncestor()); fontChooser.setSelectedFont(currentFont); fontChooser.setVisible(true); Font returnedFont = fontChooser.getSelectedFont(); if (returnedFont != null) { controller.changeElementFont(returnedFont); } } private void opacitySliderStateChanged(javax.swing.event.ChangeEvent evt) { controller.changeElementOpacity((int)opacitySlider.getValue()); } private void rotationSliderStateChanged(javax.swing.event.ChangeEvent evt) { controller.changeElementRotation((int)rotationSlider.getValue()); } private void opacitySpinnerStateChanged(javax.swing.event.ChangeEvent evt) { controller.changeElementOpacity((Integer)opacitySpinner.getValue()); } private void rotationSpinnerStateChanged(javax.swing.event.ChangeEvent evt) { controller.changeElementRotation((Integer)rotationSpinner.getValue()); } private void textDocumentChanged(DocumentEvent evt) { Document document = evt.getDocument(); try { controller.changeElementText(document.getText(0, document.getLength())); } catch (BadLocationException ex) { // Handle exception. } } Code omitted -- code for xPosition is nearly the same as for yPosition.

private void changeFontButtonActionPerformed(java.awt.event.ActionEvent evt)

INGINERIA PROGRAMRII. ndrumar de laborator

69

9) Creati intregul program urmarind cu atentie pasii de mai sus. Rulati programul si observati ce se intampla. Tocmai ati realizat un program bine proiectat dar care din pacate functiuneaza. Sa incercam sa intelegem ce se intampla si sa reparam problema. Pentru aceasta sa consideram urmatorul lant de evenimente: a. Utilizatorul actioneaza un buton b. Componenta Swing receptioneaza evenimentul si anunta listenerii c. Se cheama metoda asociata din controller d. Modelul se actualizeaza. e. Modelul notifica controlerul ca si-a schimbat valoarea f. Vizualizarea (VIEW) receptioneaza un eveniment de la controller si incearca sa reseteze valoarea componentei Swing asociate g. Metoda asociata din controller ere anuntata In acest moment in functie de component Swing utilizata si robustetea modelului utilizat se pot intampla urmatoarele: a. Componenta swing de la care a pornit modificarea refuza sa se reactualizeze stiind ca ea este chiar sursa evenimentului. Componentele text din Swing intra in aceasta categorie b. Modelul sesizeaza ca a doua cerere de update este echivalenta cu prima si nu mai trimite notificari de schimbare in acest caz. Acest model este implementat implicit in PropertyChangeSupport din pachetul java.beans. Totusi al doilea update al modelului este totusi chemat. c. Nu se pune nici un fel de conditie de siguranta (nici in model nici in componenta Swing) aplicatia cicland la infinit

INGINERIA PROGRAMRII. ndrumar de laborator

70

10) Modificati modelPropertyChange dupa urmatorul model:

if (evt.getPropertyName().equals(DefaultController.ELEMENT_X_PROPERTY)) { String newStringValue = evt.getNewValue().toString(); if (!xPositionTextField.getText().equals(newStringValue)) xPositionTextField.setText(newStringValue); }

Figura 25 Aplicatia de realizat la final

INGINERIA PROGRAMRII. ndrumar de laborator

71

7 PRINCIPII DE PROIECTARE OBIECTUALA


7.1 INTRODUCERE
Ce este arhitectura software? La cel mai inalt nivel se afla patternuri arhitecturale care definesc structura si forma aplicatiilor. La nivel putin mai adanc se afla arhitectura strans legata de scopul aplicatiei. La un nivel si mai adanc se afla arhitectura modulelor si a interconectarii acestora. Aceasta este zona patternurilor de proiectare (design patterns), a pachetelor (packages), a componentelor si a claselor.

7.2 ARHITECTURA SI DEPENDENTE


Proiectarea aplicatiilor incepe sa prinda contur intii in mitnea proiectantilor. La acest nivel, totul este clar, curat si elegant. Unele aplicatii reusesc sa pastreze puritatea designului in faza initiala a dezvoltarii produsului si chiar in primul "release". In acest moment ceva rau se poate intampla: software-ul incepe sa putrezeasca. La inceput nu este asa de rau. Se mai scrie o bucata de cod sulimentara intr-o parte, se mai modifica in alte parti, dar designul este inca multumitor de curat. Incet incet, daca se continua in acest stil, designul aplicatiei devine bolnav. Programele devin imense paduri de cod pe care dezvoltatorii le gassc tot mai greu de mentinut. In aceasta faza orice schimbare a apliatiei are efete colaterale serioase (orice schimbare este riscanta in cel mai multe cazuri terminandu-se cu insuccese).

7.3 SIMPTOMELE DESIGNULUI PUTRED


Rigiditatea. Este tendinta softwarelui de a nu suport chimbari. Schimbarile in acest caz cauzeaza o multime de schimbari in modulele dependente.

INGINERIA PROGRAMRII. ndrumar de laborator

72

Fragilitate. Aceasta este tendinta sofwarelui de a "crapa" in multe locuri la fiecare schimbare a lui. De multe ori defectul apare in arii care nu au nici o legatura dpdv concepual cu modulul ce a fost modificat. Uneori astfel de sisteme sunt imposibil de mentinut. La fiecare rezolvare unui bug, apar si mai multe problem decat s-au rezolvat. Imobilitate. Se refera la imposiilitatea reutilizarii softwarelui provenit de la alte proiecte sau chiar de la acelasi. Vascozitatea. Are doua forme: vascozitatea designului si cea a mediului. Cand sunt pusi in fata unei schimbari, inginerii gasesc mai multe posibilitati de a realiza aceasta, unele respectand designul iar altele nu. Cand metodele care respecta designul sunt mai greu de implementat decat "hack"-urile, se spune ca vascozitatea designului este mare. Vascozitatea mediului apare cand mediile de dezvoltare cu care se lucreaza sunt incete si ineficiente. De exemplu daca timpul de compilare este foarte mare, inginerii vor fi tentati sa faca schimbari care nu obliga la compilari mari, chiar daca aceste schimbari nu sunt foarte curate dpdv design.

7.4 SCHIMBAREA CERINTELOR


De multe ori se cer schimbari care nu au fost anticipate in proiectarea initiala si acestea pe deasupra mai trebuie si facute intr-un timp scurt. La acest gen de schimbari, partea periculoasa este ca ele violeaza designul original si putin cate putin lucrurile incep sa merga prost. Trebuie sa gasim intr-un fel sau altul un design inofensiv la astfel de schimbari.

7.5 MANAGEMENTUL DEPENDENTELOR.


Toate cele patru simptome mentionate mai sus sunt cauzate direct sau indirect de o dependenta improprie intre module. Pentru a se putea realiza o stapanire a dependentelor trebuiesc create niste dependency firewall-uri peste care dependentele nu se pot propaga. In continuarea acestui capitol se vor discuta diverse principii ce ajuta la controlul dependentelor.

7.6 PRINCIPII ALE PROIECTRII CLASELOR


7.6.1 PRINCIPIUL OPEN CLOSED (OCP)

INGINERIA PROGRAMRII. ndrumar de laborator

73

Un modul trebuiste sa fie deschis pentru extindere dar inchis pentru modificari. Este cel mai important principiu de proiectare oriectat obiect. Ideea e ca trebuie sa scriem modulele in asa fel incat sa poata fi extinse fara a fi necesar modificarea lor. Cu alte cuvinte dorim sa putem schimba ceea ce modulele fac fara a schimba nimic in codul acestora. Aceasta ar putea suna contradictoriu dar exista mai multe tehnici de realizare acestui lucru. Toate aceste tehnici se bazeaza pe abstractiune. Mai jos se prezinta mai multe astfel de tehnici. 7.6.1.1 Polimorfism dinamic Se dau urmatoarele structuri C++
struct Modem { enum Type { hayes, courrier, ernie} type; } struct Hayes { Modem::Type type; } struct Courrier { Modem::Type type; } struct Ernie { Modem::Type type; } si functia void LogOn(Modem& m ,string& pno, string& user, string& pw) { if (m.type == Modem::hayes) DialHayes((Hayes&)m, pno); else if (m.type == Modem::courrier) DialCourrier((Courrier&)m, pno);

INGINERIA PROGRAMRII. ndrumar de laborator

74

else ...... }

Aici fiecare tip de modem depinde de structura Modem::Type si la adaugare unui nou tip de modem, modulul trebuie remodificat si recompilat. In acest stil, codul este presarat cu sectiuni if else si pentru o modificare in acest cod trebuie platit un tribut foarte mare si anume faptul ca trebuie reanalizata intreaga clasa Modem pentru a vedea ce implicatii are modificarea. Rezolvarea acestei probleme se face prin implementarea unei arhitecturi ca mai jos.

Figura 26 - Solutie respectand OCP

Respectand OCP, functia LogOn depinde doar de interfata Modem, adaugarea unui modem nu mai are nici un impact asupra lui LogOn. In acest caz s-a creat un modul care poate fi extins fara a fi modificat. In acest caz LogOn s-a transformat in ceva de genul
void LogOn(Modem& m ,string& pno, string& user, string& pw) {

INGINERIA PROGRAMRII. ndrumar de laborator

75

m.Dial(pno); }

7.6.1.2 Problema propusa Implementati in Java arhitectura propusa mai sus. 7.6.1.3 Polimorfism static O alta tehnica de a fi conform metodei OCP este folosirea template-urilor ca in exemplul de mai jos.
template <typename MODEM> void LogOn(MODEM& m ,string& pno, string& user, string& pw) { m.Dial(pno); }

7.6.1.4 Scopurile arhitecturale ale metodei OCP Folosind aceste tehnici se pot crea module extensibile fara schimbari. Idealul poate fi foarte dificil de atins dar chiar si un OCP partial poate duce la imbunatatirea de neneglijat a structurii aplicatiei. 7.6.1.5 Un alt exemplu de incalcare OCP in Java In urmatorul exemplu vom prezenta o clasa utilizata pentru alocarea resurselor.

INGINERIA PROGRAMRII. ndrumar de laborator

76

package ro.ulbs.ip.ocpvio; public class ResourceAlocator { public int allocate(int resourceType) { int resourceId = -1; switch (resourceType) { case 2 /* TIME SLOT */: resourceId = findFreeTimeslot(); markTimeslotBusy(resourceId); break; case 3 /* SPACE SLOT */: resourceId = findFreeTimeslot(); markTimeslotBusy(resourceId); break; default: System.err.println("Attempted to allocate resource\n"); break; } return resourceId; } public int free(int resourceType, int resourceId) { switch (resourceType) { case 2 /* TIME SPLT */: resourceId = markTimeslotFree(resourceId); break; case 3 /* SPACE SLOT */: resourceId = markTimeslotFree(resourceId); break; default: System.err.println("Attempted to free resource\n"); break; } return resourceId; } private int markTimeslotFree(int resourceId) { // TODO Auto-generated method stub return 0; } private void markTimeslotBusy(int resourceId) { // TODO Auto-generated method stub } private int findFreeTimeslot() { // TODO Auto-generated method stub return 0; } }

invalid

invalid

INGINERIA PROGRAMRII. ndrumar de laborator

77

Din exemplul de mai sus se poate observa cu usurinta incalcarea principiului OCP. De cate ori se va adauga un nou tip de resurse (resourceType), codul de mai sus trebuie retestat. Programatorul ce doreste adaugarea unu nou tip de resurse trebuie sa inteleaga implementarea interna a clasei de alocare (ResourceAlocator). Codul de mai sus, se poate inlocui cu :
package ro.ulbs.ip.ocp; import java.util.Hashtable; public class ResourceAllocator { Hashtable /*<Integer, ResourcePool>*/ m_pResourcePool = new Hashtable(); int allocate(Integer resourceType) { int resourceId; ResourcePool resourcePool = resPoolByType(resourceType); resourceId = resourcePool.findFree(); resourcePool.markBusy(resourceId); return resourceId; } private ResourcePool resPoolByType(Integer resourceType) { return ((ResourcePool)m_pResourcePool.get(resourceType)); } int free(Integer resourceType, int resourceId) { resPoolByType(resourceType).markBusy(resourceId); return resourceId; } void addResourcePool(Integer resourceType, ResourcePool pPool) { m_pResourcePool.put(resourceType, pPool); } }

La adaugarea unui nou tip de resurse, codul nu mai trebuie testat nefacundu-se modificari acestuia in acest al doilea caz. Progarmatorul care doreste sa adauge noul

INGINERIA PROGRAMRII. ndrumar de laborator

78

tip de resurse nu trebuie sa cunoasca implementarea interna a ResourceAllocatorului.


ResourcePool in acest caz este OPEN la extinderi iar ResourceAllocator este

CLOSED la modificari. Cel ce adauga un nou tip de resursa trebuie doar sa cunoasca interfata ResourcePool. Care este interfata ResourcePool (se poate afla cu usurinta din codul de mai sus). Cum se implementeaza TimeslotResourcePool ? Dar SpaceslotResourcePool ? Creati codul java aferent.

7.6.2 PRINCIPIUL SUBSTITUTIEI LISKOV (LSP)


Subclasele trebuie sa poate substitui clasele de baza. Orice subclasa trebuie sa poata sa fie tratata ca parintele acesteia. Ideea este ca o clasa utilizator al unei clase de baza trebuie sa functioneze corect in continuare si daca ei ii este pasata o clasa derivata din clasa de baza.

Figura 27 - User utilizeaza Base. Derived extinde Base

Deci, conform schemei de mai sus, daca functia User accepta ca si parametru un
Base, ar trebui sa fie legala si pasarea unui parametru Derived.

Pare a fi normal sa se intample acest lucru dar sunt multe situatii care trebuiesc considerate.

INGINERIA PROGRAMRII. ndrumar de laborator

79

Exemplul clasic este dilema cerc/elipsa. 7.6.2.1 Dilema cerc/elipsa In scoala, cei mai multi dintre noi au invatat ca cercul este doar o degenerare a unei elipse. Toate cercurile sunt de fapt elipse in care focarele coincid. Aceasta "teorie" ne face sa fim tentati sa alegm un model ca in figura.

Figura 28 - Circle extinde Ellipse

Chiar daca acesta ne satisface dpdv model conceptual, sunt totusi mai multe impedimente. O privire mai atenta la declaratia elipsei incep sa faca lumina in aceasta dilema. Se observa ca elipsa are trei elmente (cele doua focare si axa mare) ceea ce pentru cerc este inacceptabil. Daca totusi nu ne-ar pasa de spatiul ocupat am putea face ca Circle sa se comporte corect, suprascriind metodele de setare a focarelor a.i. cele doua focare sa aiba aceeasi valoare. In aceste condiii am putea considera axa mare ca diametru. Totul pare sa mearga dar clientii ruineaza totul.

INGINERIA PROGRAMRII. ndrumar de laborator

80

7.6.2.2 Clientii ruineaza totul Cercurile si elipsele cu sunt singure in univers. Intre entitatile existente existe niste interfete, iar aceste interfeta implica un contract. Acest contract poate sa nu fie prevazut explicit dar el pur si simplu exista. De exemplu este foarte probabil ca un user al clasei Ellipse sa se astepte ca sectiunea de cod ce urmeazaa sa functioneze.
void f(Ellipse& e){ Point a(-1,0); Point b(1,0); e.setFoci(a,b); e.setMajorAxis(3); assert(e.getFocusA() == a); assert(e.getFocusB() == b); .... }

7.6.2.3 Design by contract

INGINERIA PROGRAMRII. ndrumar de laborator

81

Revenind la LSP, se poate spune ca pentru a fi substituabila, contractul clasei de baza trebuie sa fie onorat si de clasele derivate. Pentru exemplu dat, Circle nu onoreaza contractul pe care il implica coform extinderii lui Ellipse. Pentru a stbili contractul uni metode, trebuie sa se stie contextul in care ea va fi apelata (preconditii) si ce conditii vor fi adevarate la iesirea din metoda (postconditii). Eifel - limbaj de efinire de astfel de contracte. Deci conditiile pentru ca o clasa D sa poata inlocui clasa de baza B sunt: preconditiile lui D sa nu fie mai puternice ca le lui B postconditiile lui D sa nu fie mai slabe ca le lui B

Cu alte cuvinte clasele derivate trebuie sa nu se astepte la mai mult si s nu dea mai putin. 7.6.2.4 Repescursiuni ale violarii LSP Violarea de acest gen este greu de detectat inainte de a fi prea tarziu. (In exemplul cu cercul, ea a fost detectata cand totul parea sa mearga bine dar un client s-a plans). Uneori costurile de reparare corecta a violarii LSP sunt mult prea mari si se prfera utilizarea unor if-uri (daca e cerc sa nu mi verifice toate atributele). Se poate observa ca violarea LSP este o violare latenta OCP. 7.6.2.5 Exercitiu Se considera proiectarea unui sistem care regleaza temperatura in mai multe camere intr-un sistem. Sistemul software citeste periodic temperatura din fiecare camera si o ajusteaza la o temperatura de referinta. Comportamentul este modelat intr-o clasa de baza ControlerTemperatura. Interfata de programareeste diferita per camera (diferentele sunt manuite prin extinderea clasei de baza in cateva subclase).

INGINERIA PROGRAMRII. ndrumar de laborator

82

Controller-ul suporta urmatoareale metode : set/get ReferenceTemperature : nu sunt metode virtuale deoarece

temperatura de referinta nu este dependenta de vreun dispozitiv de intrare iesire. Initialize : initializeaza adresa portului getTemperature : metoda pur virtuala, registri pentru citirea temperaturii

difera de la dispozitiv la dispozitiv. adjustTemperature : aplica ajustajul aplicat ca parametru. Metoda este pur

virtuala, implementarea acesteia difera de la dispozitiv la dispozitiv. Creati clasa ControlerTemperatura cu cele patru metode. Creati o clasa
ControlerTemperaturaFirmaX

care

implementeaza

getTemperature astfel : return io_read(254). Metoda adjustTemperature sa

ve realiza prin utilizarea io_write(253, temperatura). Implementati io_read si io_write ca doua metode goale in ControllerTemperatura. Se poate crea inca o clasa ControlerTemperaturaFirmaY pentru care portul de intrare iesire este altul. Sa presupunem acum ca departamentul de marketing decide sa suporte si controlerele de temperatura produse de firma Z. Din pacate, dispozitivele produce de firma Z nu sunt perfect compatibile cu ControllerTemperatura : Z produce dispozitive automate in care se programeaza temperatura de referinta. Intreg ciclul de ajustare este facut automat. Tentatia este de a realiza o clasa ControlerTemperaturaFirmaZ in care se face o implemetare blank pentru metoda
adjustTemperature

iar

set/getReferenceTemperatura vor opera direct cu dispozitivul.

INGINERIA PROGRAMRII. ndrumar de laborator

83

Totul pare bine la prima vedere dar sa presupunem ca softul de management este realizat astfel:
ControlerTemperatura tempController = next() ; tempController.setReferenceTemperature(10) ; tempController.initialize() ; x = tempController.getTemperature() ;

Se observa ca dispozitivul de initializeaza dupa ce dj s-au apelat functii hardware din acesta, ceea ce poate duce la rezultate haotice (chiar la defectarea sistemului).

7.6.3 PRINCIPIUL DEPENDENTEI INVERSE (DIP)


Sa depinzi de abstract. Sa nu depinzi de concret. Modulele de nivel inalt nu trebuie sa depinda de cele de sub ele. Amble trebuie sa depinda de abstractiuni. Daca OCP exprima scopul arhitecturii OO, DIP exprima mecanismul principal. Este vorba de fapt de forta din spatele proiectarii componentelor, COM, CORBA, EJB ... . Intr-o diagrama a modulelor unei aplicatii se observa ca modulele de nivel mai inalt depind de modulele de nivel mai scazut (API ... ) - acest gen de dependenta structurala este una slaba.

Figura 29 - Dependenta top - down

INGINERIA PROGRAMRII. ndrumar de laborator

84

Arhitectura OO arata o alta structura de dependente unde clasele de nivel mai inalt depind de abstractiuni.

Figura 30 - Evitarea dependentei top - down internivel

In acest caz detaliile depind de abstractiunile de nivel mai inalt ci nu invers dependenta a fost inversata. 7.6.3.1 Dependenta de abstractiuni Implicatia acestui principiu este simpla: dependentele trebuie sa aiba ca tinta clase abstracte nu concrete. Motivul este si el simplu: lucrurile concrete se schimba frecvent. Tehnologiile cum sunt COM ne obliga la respectarea acestui principiu (intre componente) din moment ce doar interfata abstracta a componentei este vizibila. 7.6.3.2 Crearea obiectelor Unul dintre locurile unde nu se pot face dependente la clase abstracte este crearea obiectelor (nu se pot crea obiecte abstracte). Aparent nu exista nici o posibilitate de

INGINERIA PROGRAMRII. ndrumar de laborator

85

a iesi din acest impas dar totusi exista o solutie eleganta numita AbstractFactory - un pattern ce va fi studiat mai tarziu. 7.6.3.3 Exemplu Sa presupunem ca dorim sa realizam o stiva de protocoale RLC (radio link control). Cele trei nivele sunt : RLC Physical Layer, RLC Datalink Layer si RLC Network Layer. Fiecare nivel este modelat ca o clasa. Un scheleton al acestora (in C++) este prezentat mai jos :

INGINERIA PROGRAMRII. ndrumar de laborator

86

class RLC_Physical_Layer { RLC_Datalink_Layer *m_p_RLC_Datalink_Layer; public: void Device_Transmit(Datagram *p_Datagram) { Apply_Physical_Layer_Headers(p_Datagram); Write_Message_To_Device(p_Datagram); } void Handle_Device_Receive(Datagram *p_Datagram) { Remove_Physical_Layer_Header(p_Datagram); m_p_RLC_Datalink_Layer->Handle_Physical_Layer_Receive(p_Datagram); } }; class RLC_Datalink_Layer { RLC_Physical_Layer *m_p_RLC_Physical_Layer; RLC_Network_Layer *m_p_RLC_Network_Layer; public: void Datalink_Transmit(Datagram *p_Datagram) { Process_Datalink_Transmit(p_Datagram); m_p_RLC_Physical_Layer->Device_Transmit(p_Datagram); } void Handle_Physical_Layer_Receive(Datagram *p_Datagram) { Process_Datalink_Receive(p_Datagram); m_p_RLC_Network_Layer->Handle_Network_Layer_Receive(p_Datagram); } }; class RLC_Network_Layer { RLC_Datalink_Layer *m_p_RLC_Datalink_Layer; Application_Layer *m_p_Application_Layer; public: void Network_Transmit(Datagram *p_Datagram) { Process_Network_Layer_Transmit(p_Datagram); m_p_RLC_Datalink_Layer->Datalink_Transmit(p_Datagram); } void Handle_Datalink_Layer_Receive(Datagram *p_Datagram) { Process_Network_Layer_Receive(p_Datagram); m_p_Application_Layer->Handle_Application_Receive(p_Datagram); } };

Rescrieti codul de mai sus in Java.

INGINERIA PROGRAMRII. ndrumar de laborator

87

Problema majora cu acest cod este faptul ca cele trei clase depind unele de altele, unele avand nevoie de celelalte pentru a-si realiza taskul. Relatiile intre nivele sunt cablate. Nu se poat asambla protocoale noi prin asamblarea a noi seturi de nivele. Schimbari de proiectare intr-un nivel pot avea repercursiuni majore in celelalte. Modificati arhitectura prin introducerea unei clase Nivel Generic . Elementele acestei clase abstracte sunt : un constructor cu doi paramtetrii (nivelul de deasupra si cel de dedesupt), fiecare layer, cand primeste un mesaj de deasupra lui face ce trebuie sa faca iar apoi trimite nivelului de dedesupt mesajul pentru a fi procesat mai departe, cand se receptioneaza un mesaj de la nivelul de dedesupt se proceseaza mesajul si se trimite in sus. Realizati cele patru clase in java. Creati un alt nivel Datalink si observati ca se poate utiliza acelasi nivel fizic fara a modifica vreo linie de cod in acesta. Interpuneti un layer de debug intre nivelul fizic si cel de deasupra lui care nu face altceva decat paseaza mesajele mai departe si scrie niste scurte mesaje.

7.6.4 PRINCIPIUL SEGREGARII INTERFETELOR (ISP)


Mai multe interfee specifice unui client sunt de preferat unei singure interfee generale. Daca avem o clasa care are mai muli clieni, este mai bine sa existe interfee specifice pentru fiecare client dect sa se ncarce clasa cu toate metodele necesare tuturor clienilor.

INGINERIA PROGRAMRII. ndrumar de laborator

88

Figura 31 - Segregarea interfetelor

Daca mai multi clienti au nevoie de aceeasi interfata nu mai este necesara o interfata pentru fiecare client.

7.7 PRINCIPIILE ARHITECTURII PACHETELOR


Clasele sunt necesare dar nu suficiente pentru design. Problema care se pune este ca nu vom sti fiecare clasa din ce pachet face parte? Sunt prezentate mai jos trei principii cunoscute ca Principii de coeziune a pachetelor care au ca scop ajutarea arhitectilor de soft.

7.7.1 PRINCIPII DE COEZIUNE


Principiul ehivalentei realizare reutilizare (REP) Unitatea ce se reutilizeaza este unitatea produsa O componenta care nu este in faza de productie nu poate fi reutilizata, utilizatorii acesteia fiind nestisfacuti de schimbarile dese ce apar in fazele premergatoare productiei (release).

INGINERIA PROGRAMRII. ndrumar de laborator

89

Un criteriu de grupare a claselor in pachete este dupa utilizarea lor, pachetul fiind unitatea de release, normal ca tot pachetul este si unitatea ce se refoloseste. Prinipiul inchiderii comune (CCP) Clasele care se schimba impreuna, apartin aceluiasi pachet Un proiet de dezvoltare mare este impartit intr-un numar mare de pahete interconectate. Cand un pachet se schimba, cantitatea de munca pentru recompilarea tuturor dependentelor poate fi foarte mare ceea ce ne duce cu gandul la o metoda de minimizare a numarului de pachete ce trebuiesc compilate/testate : grupam in acelasi pachet clasele care se schimba impreuna. Avantajul este mare dar si dificultatea de a detecta in avans clasele care sunt dependente si sufera modificari impreuna este mare. Principiul reutilizarii comune (CRP) Clasele care nu sunt foloite impreuna nu trebuisc grupate in acelasi pachet Tensiunea intre principiile de coeziune a pachtelor Problema cu cele trei principii de mai sus este ca ele sunt mutual exclusive (nu pot fi respectate in acelasi timp). REP, CRP fac viata mai usoara celor care reutilizeaza modulele in timp ce CCP se gandeste mai mult la creatorii pachetului (sau la cei ce se ocup de mentenanta). CCP - un singur pachet; CRP - foarte mici ... . Din fericire pachetele nu sunt "batute'n cuie" ele se pot schimba pe parcursul dezvoltarii softului fara mari probleme.

7.7.2 PRINCIPII DE CUPLARE


7.7.2.1 Principiu dependentei aciclice (ADP) Dependentele intre pachete trebuie sa nu formeze cicluri

INGINERIA PROGRAMRII. ndrumar de laborator

90

Din moment ce unitatea de release este pachetul, cei care lucreaza prefera sa o faca in interiorul unui singur pachet (sa nu lucreze in mai multe pachete deodata). Aceasta tendinta este amplificata de principiile de coeziune care incerca sa tina impreuna clasele care au legatura intre ele. Inainte de a face release unui pachet, ei trebuie sa il testeze si pentru acesta, ei trebuie sa compileze si sa testeze toate pachetele care depind de cel caruia tocmai iau facut release.

Figura 32 - Aplicatie structurata corect, fara dependente ciclice

Considerand figura de mai sus, daca se doreste livrarea pachetului Protocol, el trebuie sa se bazeze pe ultima versiune a pachetului CommError. Protocol nu mai are alte dependente.

INGINERIA PROGRAMRII. ndrumar de laborator

91

Problema apare daca o clasa din CommError dorete sa afieze ceva folosind o componenta din GUI => s-a realizat o dependenta de GUI.

Figura 33 - Aplicatie cu cicluri puternice

In acest caz, cel ce livreaza Protocol, trebuie sa-si creeze suita de test cu pachetele: CommError, GUI, Comm, ModemControl, Analysis, Database, ceea ce este dezastruos. Pentru a se evita astfel de dezastre, trebuie sa existe cineva care sa asigure inexistenta ciclurilor de dependente intre pachete.

INGINERIA PROGRAMRII. ndrumar de laborator

92

Figura 34 - Evitarea ciclurilor prin introducerea unui modul abstract

Pentru ruperea ciclurilor exista doua metode: prima este crearea unui nou pachet MessageManager, clasele din GUI de care avea nevoie ComError sunt mutate in MessageManager si astfel atat GUI cat si CommError depind de MessageMnager, a doua este prin utilizarea DIP si ISP.

INGINERIA PROGRAMRII. ndrumar de laborator

93

Figura 35 Utilizare DIP si ISP. Daca A depinde de X si Y depinde de B se mai poate adauga o interfata BY care are toate metodele de care are neoie Y. Interfetele e bine s fie plasate in pachetel cu clasele care au nevoie de ele nu in clasele ce le implementeaza

7.7.2.2 Principiul dependentelor stabile (SDP) Depinde in directia stabilitatii Stabilitatea. Daca se pune un banut in dunga ... sta dar nu se poate spune ca este stabil. Stabilitatea se refera la cantitatea de efort ce trebuie depus pentru a se face o schimbare. Banutul nu e stabil pentru ca el se rastoarna la cea mai mica incercare. In contrast cu banutul, masa pe care sta, este stabila. Care este legatura cu programarea? Exista mai multi factori care fac un pachet greu de modificat (dimensiuea, complexitatea, claritatea ... dar cel mai important este multitudinea de pachete care depind de cel luat in analiza). Un pachet cu multe dependente de intrare este foarte stabil (X).

INGINERIA PROGRAMRII. ndrumar de laborator

94

Figura 36 - Pachet foarte stabil

Pe de alta parte un pachet de care depind foarte putini este putin stabil (la limita ... iresponsabil) (Y). Daca X nu depinde de nimeni spunem ca este independent. Metrici de stabilitate. Stabilitatea unui pachet se poate determina folosind 3 metrici: Ca (Afferent Coupling) - Numarul de clase in afara pachetului care depind de clase din interiorul lui (ingoing dep) Ce (Efferent Coupling) - Numarul de clase din afara pachetului, pentru care clase din pachet depind de ele (outgoing dep) I (Instability) - I = Ce / (Ca + Ce) apartine [0..1]. Acum s-ar putea reformula SDP "Depinde de pachete al carui I este mai mic ca al tau".

INGINERIA PROGRAMRII. ndrumar de laborator

95

Figura 37 - Y, pachet iresponsabil

Intrebarea este daca tot softul trebuie sa fie stabil ? Unul dintre cele mai importante semne designului bun este usurinta cu care acesta se poate modifica. Din aceasta cauza se doreste ca unele parti sa fie instabile.

Figura 38 - Exemplu violare SDP

Cosiderand figura de mai sus vom arata cum SDP poate fi violat. Flexible este un pachet care dorim sa fie usor de modificat. Sa presupunem ca dezvoltatori ai pachetului Stable, realizeaza o dependenta la Flexible. Acesta, violeaza SDP din

INGINERIA PROGRAMRII. ndrumar de laborator

96

cauza ca un pachet care se doreste stabil depinde de unul cre se doreste instabil. Ca rezultat, Flexibile nu mai este usor de modificat, orice schimbare avand ca urmare schimbari in Stable si pachetele care depind de acesta. 7.7.2.3 Principiul stabilitatii abstracte (SAP) Pachetele stabile trebuie sa fie abstracte Putem sa ne imaginam sructura de pachete a aplicatiei noastra ca un set de pachete intrconectate, cu pachetele instabile in partea de sus iar cele stabile in partea de jos. In acest imagine, dependentele merg inspre cele stabile. Pachetele de sus sunt usor de modificat dar modificarea celor de jos are un impact foarte puternic. Intrebare care se pune este : Dorim in proiect sa existe pachete greu de modificat? In mod sigur, orice pachet greu de modifict duce la lipsa de flexibilitate. Exista totusi o gaura neagra pe care o putem specula: Pachetele stabile sunt greu de modificat dar daca au fost facute corect sunt usor de extins (utilizand OCP). De fapt SAP este doar o reformulare a DIP. Cele mai stabile pachete trebuie s fie cat mai abstracte. Dar cum se masoara gradul de abstractie? Metrici de abstractie.
Nc - numarul de clase din pachet Na - numarul de clase abstracte din pachet A - A=Na/Nc

SAP vazut prin prisma A si I: I trebuie sa cresca cand A scade. Deci pachetele concrete trebuie sa fie instabile iar cele abstracte stabile.

INGINERIA PROGRAMRII. ndrumar de laborator

97

Figura 39 - Dependenta intre I si A

Din figura de mai sus rezulta ca daca A este mare si I este mare, nu are sens. Daca A mic si I mic (sub dreapta) pachetul se ncadreaz in "zona de suferita". Deci frumos ar fi I=1-A dar in realitate nu este posibil. Metrici de distanta D Distanta D=abs(A+I-1)/sqr(2) intre 0 si 0.707 D' Distanta normalizata. D=abs(A+I-1). variaz intre 0 si 1. Aceste metrici msoar arhitectura orientata obiect.

INGINERIA PROGRAMRII. ndrumar de laborator

98

8 SABLOANE DE PROIECTARE
Ideea esentiala a sabloanelor de proiectare este reutilizarea unor solutii consecrate la probleme cu probabilitate mare de reaparitie. In general pattern-urile sunt descrise prin: Nume : descrie pe scurt problema ce o rezolva Scop: carui tip de probleme i se adreseaza Motivatie: Exemplu adecvat de problema rezolvata Problema: Desciere pe larg a problemei si a contextului de aparitie Solutia: Descrierea elementelor utilizate si a relatiilor dintre acestea. Consecinte: Orice solutie are implicatii (bune si rele). Acest capitol analizeaza impactul asupra flexibilitatii, extensibilitatii sau portabilitatii sistemului, dupa cum pot sa se refere la aspecte ale implementarii sau limbajului de programare utilizat. Compromisurile sunt de cele mai multe ori legate de spatiu si timp. Creationale Clasa Factory Method Structurale Adapter (class) Comportamentale Interpreter Template Method Chain of Responsibility Abstract Factory Adapter (object) Obiect Builder Prototype Singleton Bridge Composite Decorator Facade Flyweight Command Iterator Mediator Memento Observer State

INGINERIA PROGRAMRII. ndrumar de laborator

99

Proxy

Strategy Visitor

8.1 CATEVA OBSERVATII GENERALE LEGATE DE OOP


8.1.1 CARACTERIZAREA MOSTENIRII
este definita static, la compilare si poate fi specificata direct, fiind suportata explicit de limbajele de programare; permite modificarea usoara a implementarii operatiilor reutilizate, si anume intr-o subclasa care redefineste o parte din operatiile clasei parinte pot fi afectate si operatii mostenite, daca acestea apeleaza operatii redefinite. implementarea mostenita de la clasele parinte nu poate fi modificata la momentul executiei; cel mai adesea clasele parinte definesc cel putin partial reprezentarea fizica a subclaselor lor, deci subclasele au acces la detalii ale implementarii superclaselor. De aceea se mai spune ca mostenirea de clasa incalca principiile incapsularii; modificarile aduse implementarii unei superclase vor forta subclasele sa se modifice si ele. Dependentele de implementare pot cauza probleme atunci cand se incearca reutilizarea subclaselor: daca anumite aspecte ale implementarii mostenite nu corespund necesitatilor aplicatiei clasa parinte trebuie rescrisa sau inlocuita. Aceasta dependenta limiteaza flexibilitatea si, in ultima instanta, reutilizarea. O solutie in acest caz ar fi aplicarea mostenirii de la clase abstracte, deoarece ele includ implementare in mica masura.

8.1.2 COMPUNEREA OBIECTELOR


se defineste in mod dinamic, la executie, prin faptul ca anumite obiecte

INGINERIA PROGRAMRII. ndrumar de laborator

100

primesc referinte ale altor obiecte; necesita ca obiectele sa-si respecte unul altuia interfata, ceea ce presupune ca interfetele sa fie proiectate astfel incat sa nu impiedice utilizarea unui obiect in combinatie cu mai multe tipuri de obiecte. Deoarece obiectele sunt accesate doar prin intermediul interfetelor, nu este incalcat principiul incapsularii. In decursul executiei orice obiect poate fi inlocuit cu altul, atata timp cat obiectele respective au acelasi tip. In plus, datorita faptului ca si implementarea unui obiect este scrisa tot in termenii interfetelor altor obiecte, dependentele de implementare vor fi substantial reduse; prin compunerea obiectelor se obtin urmatoarele efecte asupra unui proiect: clasele sunt incapsulate si "concentrate" asupra cate unui singur obiectiv, ceea ce face ca ele, ca si ierarhiile lor sa aiba dimensiuni mici si sa fie mai usor de gestionat. Un proiect bazat pe compunerea obiectelor se caracterizeaza printr-un numar mai mare de obiecte si un numar mai mic de clase, iar comportarea sistemului va depinde de relatiile dintre obiecte, in loc sa fie definita de o anumita clasa.

Experienta arata ca adesea proiectantii folosesc mostenirea in mod abuziv. De aceea se recomanda studiul si aplicarea sabloanelor de proiectare, acestea bazandu-se foarte mult pe compunerea obiectelor.

8.1.3 DELEGAREA
Reprezinta o cale de aplicare a principiului compunerii obiectelor. Intr-o relatie de delegare 2 obiecte sunt implicate in rezolvarea unei cereri, si anume: obiectul care recepteaza mesajul (delegatorul) deleaga executia operatiei corespunzatoare unui alt obiect - delegat. Acest lucru este oarecum similar cu situatia in care subclasele "paseaza" sarcina executiei unor operatii claselor parinte (este vorba despre operatiile mostenite si

INGINERIA PROGRAMRII. ndrumar de laborator

101

neredefinite). Dar, in timp ce clasa parinte a unei subclase ramane aceeasi pe toata durata executiei, in cazul delegarii obiectele delegat pot fi schimbate, cu conditia sa aiba aceeasi interfata. Delegarea este considerata ca un sablon de proiectare fundamental, pe ea bazanduse foarte multe din celelalte sabloane (ex: State, Visitor, Strategy, Mediator, Chain of Responsibility, Bridge). Capitolul urmator, trateaza problema delegarii mai pe larg.

INGINERIA PROGRAMRII. ndrumar de laborator

102

9 DELEGARE (DELEGATION)
Aceasta lucrare prezinta principiul delegarii, necesitatea acestuia si solutiile de implementare.

9.1 MOTIVATIE:
In dezvoltarea aplicatiilor software se intalnesc adesea utilizari inadecvate ale mostenirii, care sunt considerate "anti-sabloane". Printre acestea cele mai frecvente sunt: a) derivarea din clase de uz general (gen Vector, HashTable etc). Declararea unei clase care modeleaza o entitate dependenta de aplicatie ca subclasa a unei clase de uz general nu este recomandata, din urmatoarele motive:
o o

modificarea clasei generale poate afecta subclasele; de obicei derivarea se face pentru utilizarea functiilor din clasa de uz general. Acest lucru nu este neaparat rau dar poate distruge incapsularea: clientii clasei specifice pot miza pe faptul ca acea clasa extinde clasa de uz general (rezulta dependenta de clasa generala).

Un exemplu de folosire inadecvata a mostenirii il intilnim chiar in Java, unde clasa care implementeaza stiva (Stack) mosteneste clasa Vector. public class Stack extends Vector Datorita mostenirii un programator poate sa apeleze pentru o variabila de tip Stack metode care apartin clasei de baza Vector, ca in exemplul prezentat mai jos:
Stack stiva = new Stack(); stiva.push("X"); stiva.push("Y"); stiva.push("Z");

INGINERIA PROGRAMRII. ndrumar de laborator

103

Object x = stack.get(1);

Dupa cum se observa aceasta stiva expune metode de acces ale vectorului ceea ce nu este tocmai dorit. (Conform contractului trebuie sa aiba doar push si pop). b) folosirea mostenirii pentru modelarea rolurilor. Ca sa ne dam seama cand suntem pe cale sa aplicam mostenirea in mod nepotrivit, iata doua dintre criteriile pe care le putem aplica:

Se utilizeaza mostenirea doar cand aceasta este cu predilectie statica. Daca se constata ca un anumit obiect, la momente de timp diferite, trebuie sa apartina unor subclase diferite ale aceleiasi clase parinte B, o asemenea situatie nu se va modela folosind mostenirea de clasa. Cu alte cuvinte, mostenirea nu este potrivita atunci cand identificam o situatie in care se schimba clasa de baza in timpul executiei. Daca se constata ca o anumita subclasa trebuie sa ascunda fata de clientii sai o parte din membrii mosteniti de la parintele ei avem un semn ca aplicarea mostenirii nu a fost cea mai inteligenta solutie.

O alta solutie de a afla daca trebuie sa folosim mostenire sau delegare este de a raspunde la urmatoarea intrebare A fi sau a avea?. In diagrama de mai jos este prezentat un exemplu in care clasele Programator si Director mostenesc clasa Angajat. Totul pare sa fie corect, insa exista situatii in care un angajat este programator iar mai apoi director. In aceste situatii modelul prezentat nu mai poate sa fie folosit.

INGINERIA PROGRAMRII. ndrumar de laborator

104

Figura 40 - Programator si Director mostenesc Angajat

Pentru a rezolva problema aparuta putem sa folosim in locul mostenirii delegare, ca in diagrama urmatoare, unde clasa Angajat poate sa contina membrii de tip
Programator, Director.

INGINERIA PROGRAMRII. ndrumar de laborator

105

Figura 41 - Un angajat poate avea rolul de Programator, Director sau chiar ambele

9.2 APLICABILITATE:
in cazurile in care metode sau membrii mosteniti nu trebuie sa fie accesati in clasa derivata - in cazul in care comportamentul unei clase este determinat in timpul executiei (O fereastra poate fi in timpul executiei dreptunghiulara sau rodunda, deci nu ar fi bine ca clasa fereastra sa mosteneasca clasa dreptunghi). Delegarea este utilizata in alte pattern-uri cum ar fi State, Strategy si Visitor, pattern-uri ce vor fi analizate in lucrarile urmatoare.

9.3 STRUCTURA:

Figura 42 - Structura delegare

INGINERIA PROGRAMRII. ndrumar de laborator

106

9.4 PARTICIPANTI:
Delegator clasa delegator care are membru de tipul Delegat; Delegat clasa (de obicei de uz general) a carei functionalitate va fi folosita de catre delegator si nu va fii neaparat expusa de Delegator clientilor; Clasa Delegator va folosi unele dintre metodele si membrii clasei delegate pentru a realize propriile obiective.

9.5 COLABORARE:

9.6 CONSECINTE:
Principalul dezavantaj al delegarii este gradul mai scazut de structurare fata de mostenire. Relatiile dintre clase modelate cu ajutorul delegarii sunt mai putin clare. Pentru rezolvarea acestor neajunsuri se pot utiliza reguli privind alegerea numelor pentru a referi obiectele aflate in diverse roluri si utilizarea comentariilor pentru clarificarea scopului delegarii. Delegarea este mai generala decat mostenirea. Orice extensie adusa unei clase prin mostenire se poate realiza si prin delegare. Delegarea este o buna alegere in proiectare, dar trebuie avut grija ca ea sa nu fie folosita inadecvat.

9.7 IMPLEMENTARE:
public class Delegator { Delegat d; . . . public type metodaDelegator() { . . . d.metodaDelegat(); . . . } };

class Delegat { public type metodaDelegat() { . . .

INGINERIA PROGRAMRII. ndrumar de laborator

107

return type; } };

9.8 PROBLEME PROPUSE:


1. Implementati o clasa care sa ofere functionalitatea unei structuri de date de tip coada. Clasa respectiva va folosi prin delegare un membru private de tip java.util.Vector. 2. Implementati clasa de mai sus prin mostenire de Vector si remarcati diferentele. 3. Implementati o clasa care sa ofere functionalitatea unei structuri de date de tip stiva. Clasa respectiva va folosi prin delegare un membru privat de tip java.util.Vector.

INGINERIA PROGRAMRII. ndrumar de laborator

108

10 FACTORY METHOD
10.1 SCOPUL
Definete o interfa pentru crearea unui obiect, dar las subclasele s decid care clas va fi instaniat.

10.2 ALSO KNOWN AS


Constructor Virtual

10.3 MOTIVAREA

Figura 43 - Factory Mathod

Un Framework utilizeaza clase abstracte pentru a defini i menine relaiile dintre obiecte si este adesea responsabil i de crearea acestor obiecte. Considerm un Framework pentru aplicaii care utilizeaza documente (*.doc, *.mp3, etc). Dou abstracii de baz sunt clasele Aplication i Document. Ambele clase sunt abstracte i clienii trebuie s le creeze subclase pentru a realiza implementri specifice aplicaiilor. Pentru a crea o aplicaie de desenare de exemplu, definim clasele DrawingAplication i DrawingDocument. Clasa aplicaie va fi responsabil de administrarea documentelor i le creaza la cerere cnd utilizatorul selecteaz Open sau New din meniu.

INGINERIA PROGRAMRII. ndrumar de laborator

109

Datorit faptului c subclasa concreta (aici MyDocument dar pentru aplicatii reale are nume diferite) care trebuie instaniat este specific aplicaiei (aplicatie pe care inca nu am proiectat-o !!), clasa Application nu poate prediciona instanierea clasei documentului; aceasta tiind numai cand trebuie creat un nou document fr a cunoate de ce tip este acesta. Aceasta creaz o dilem: cadrul trebuie s instanieze clase dar el nu cunoate dect clase abstracte care nu pot fi instaniate. Pattern-ul Factory Method ofer o soluie. El ncapsuleaz cunotinele despre ce subclas a clase Document trebuie creat i mut aceste cunotine n afara cadrului.

10.4 APLICABILITATEA
Factory Method se folosete cnd: O clas nu poate anticipa clasa obiectelor care trebuie create; O clas dorete ca tipul exact al obiectelor care se instantiaza sa fie specificat de clasele descendente;

10.5 STRUCTURA

produs

Figura 44 - Structura sablonului FactoryMethod

10.5.1 PARTICIPANI
Product (Document) definete interfaa obiectelor pe care le creeaz metoda factory

INGINERIA PROGRAMRII. ndrumar de laborator

110

ConcretProduct (MyDocument) Implementeaz interfaa Product

Creator (Application) Declaraiile metodei factory, care returneaz un obiect de tip Product Poate apela metoda factory pentru a crea un obiect Product

ConcretCreator (MyApplication) Rescrie metoda factory pentru a returna o instan a ConcretProduct.

10.6 CONSECINELE
Metodele Factory elimin hard-coding-ul. In cod se lucreaz numai cu interfaa clasei Product, ca urmare va lucra cu orice clas concret definit de utilizator care extinde Product. Un dezavantaj potenial: clienii trebuie s deriveze clasa Creator numai pentru a crea un obiect particular Concrte Product. Derivarea nu creaz probleme cnd clientul trebuies deriveze oricum clasa Creator, dar altfel sunt obligat sa-l am tata pe Creator si poate nu vreau. n continuare sunt prezentate nc dou consecine ale pattern-ului Factory Method: Furnizeaz hooks pentru subclase. Crearea obiectelor unei clase cu metoda factory este mai flexibil dect crearea obiectului direct. Daca Factory Metod nu este abstracta, ofera o implementare implicita pentru obecte de tip ConcreteProduct. Daca doresc sa modific, in clasele descendente rescriu FactoryMethod. Conecteaz n ierarhiile paralel de clase. n exemplul precedent metoda factory este apelat numai de constructor. Dar acesta nu este un exemplu tipic; clienii vor gsi acest metod folositoare n special n cazul ierarhiilor de clase paralele.

INGINERIA PROGRAMRII. ndrumar de laborator

111

Ierarhiile de clase paralele se obin atunci cnd o clas transmite o parte din responsabiliti unei clase separate. De exemplu figurile grafice care pot fi manipulate interactiv, adic poate fi mutat sau rotit folosind mouse-ul. Implementarea unor astfel de interaciuni nu este ntotdeauna uoar. Adesea este necesar memorarea i modificarea informaiei care nregistreaz starea manipulrii la un moment dat. Aceast stare este necesar numai n timpul manipulrii, mai mult ea nu este necesar n obiectul figur. Diferite figuri se comport diferit cnd utilizatorul le manipuleaz. De exemplu, ntinderea unei linii ar putea avea ca efect mutare unui capt al acesteia n timp ce ntinderea unui text poate schimba distana dintre linii. Solutia : o ierarhie separata de manipulatoare. CreateManipulator() este FactoryMethod care creaza manipulatorul corespunzator figurii care are nevoie de el.

INGINERIA PROGRAMRII. ndrumar de laborator

112

11 ABSTRACT FACTORY
11.1 SCOP
Furnizeaz o interfa pentru crearea unor familii de obiecte nrudite sau dependente, fr a specifica clasele lor concrete.

11.2 MOTIVAREA
S considerm o aplicaie care suport mai multe moduri de pr ezentare, cum ar fi Motif i Presentation Manager. Diferitele moduri de prezentare implic diferite imagini si comportamente pentru componentele interfeei utilizator, cum ar fi scrollbar-uri, ferestre i butoane.

Figura 45 - aplicatie ce suporta moduri de prezentare multiple

11.3 ALSO KNOWN AS


Kit

11.4 CAND SE UTILIZEAZA


Folosii pattern-ul Abstract Factory cnd: Sistemul trebuie s fie independent de modul n care produsele sale sunt create compuse i reprezentate.

INGINERIA PROGRAMRII. ndrumar de laborator

113

Sistemul trebuie s fie configurat una sau mai multe familii de produse. Se doreste proiectarea unei familii de produse inrudite care s lucreze mpreun i aceast constrngere ar trebui pstrat.

Se dorete furnizarea unei librri de produse si dorim sa facem publica interfata acestora dar nu si implementarea.

INGINERIA PROGRAMRII. ndrumar de laborator

114

11.5 STRUCTURA

Figura 46 - Structura generica AbstractFactory

11.5.1 PARTICIPANTS
AbstractFactory - declara o interfaa pentru operaii de creare a produselor abstracte; ConcreteFactory - implementeaza operatiile de creare a produselor concrete; AbstractProduct - declara o interfata pentru o categorie de produse; ConcreteProduct - definete un produs care va fi creat de un obiect ConcreteFactory corespunztor; - implementeaza interfaa AbstractProduct; Client - utilizeaz doar interfeele AbstractFactory si AbstractProduct.

11.6 CONSECINELE
Izoleaz clasele. Pattern-ul Abstract Factory ofer posibilitatea controlului claselor cnd o aplicaie este creat. Din cauz c o clas de tip factory ncapsuleaz responsabilitile i procesele de creare a obiectelor, se izoleaz clienii de implementarea claselor. Clienii manipuleaz instanele prin interfeele lor abstracte. Numele clasei este izolat n implementare, el nu apare n codul clientului.

INGINERIA PROGRAMRII. ndrumar de laborator

115

Face mai uor schimbul ntre familiile de produse. Clasa concret factory apare o singur dat, numai la instaniere. Aceasta o face mai uor de schimbat clasa pe care o utilizeaz aplicaia. Se pot folosi diferite configuraii ale produsului simplu prin schimbarea clasei Concrete Factory. Datorit faptului c o clas factori abstract creaz o familie de produse, ntreaga familie se schimb simultan. n exemplul nostru de interfa putem schimba ntre Motif i Presentation Manager prin schimbarea obiectului factory corespunztor i recrearea interfeei. Asigura consistena dintre produse. Cnd se creeaz obiecte ntr-o familie acestea sunt proiectate s lucreze mpreun, este important ca acea aplicaie s foloseasc obiectele provenite de la o singur familie la un moment dat. Pattern-ul abstract factory face aceasta uor de aplicat. Suportarea noilor tipuri de produse este dificil. Extinznd pattern-ul i la producerea de noi tipuri de produse nu este uor. Aceasta din cauz c interfaa pattern-ului fixeaz un set de produse care pot fi create. Suportarea noilor tipuri de produse implic extinderea interfeei, care complic schimbarea clasei AbstractFactory i toate subclasele sale.

11.7 PATTERN-URI NRUDITE


Clasa Abstract Factory este adesea implementat cu metode factory (Factory Method), dar poate fi implementata si folosind Prototype. O clas concret factory este adesea un Singleton

INGINERIA PROGRAMRII. ndrumar de laborator

116

12 SINGLETON
12.1 SCOPUL
Asigur c o clas are o singur instan i furnizeaz un punct global de acces la ea.

12.2 MOTIVAREA
Exista situatii in care unele clase trebuie s aib exact o singur instan. De exemplu la pattern-ul AbstractFactory este necesar sa existe o singura fabrica concreta (altfel incurc produsele).

12.3 APLICABILITATEA
Patternul Singleton se folosete cnd: trebuie s existe o singur instan a unei clase i trebuie s fie accesibil clienilor din diferite puncte de acces; cnd o singur instan ar trebui extins n subclase i clienii ar trebui s foloseasc instana extins fr a se modifica codul.

12.4 STRUCTURA

INGINERIA PROGRAMRII. ndrumar de laborator

117

12.5 IMPLEMENTARE IN JAVA


public class MySingleton { private static MySingleton _instance = new MySingleton(); private MySingleton() { // constructor privat } public static MySingleton getInstance() { return _instance; } // alte metode . . . }

O alta posibilitate evidentiaza tehnica cunoscuta sub numele lazy initialization:


public class MySingleton { private static MySingleton _instance; private MySingleton() { //. . . } // lazy initialization public static synchronized MySingleton getInstance() { if (_instance==null) { _instance = new MySingleton(); } return _instance; } //alte metode. . . }

Ambele solutii au o posibila problema: daca vreau sa extind clasa metoda getInstance() nu mai poate fi suprascrisa polimorfic (deoarece este statica = metoda de clasa) O alta varianta : cream o clasa SingletonFactory care mentine o tabla de dispersie, unde perechile <key, value> sunt <nume, singleton> (detalii in Design Patterns)

12.6 PROBLEMA PROPUSA


1. Creati o clasa PrinterPooler. Clasele client pot crea maxim 5 instante de PrintPooler indiferent de cate cereri se fac. Dupa finalizarea metodei print,

INGINERIA PROGRAMRII. ndrumar de laborator

118

instanta respectiva este marcata ca libera si poate sa fie reutilizata (la cererea urmatoare). Cu alte cuvinte un client va face:
printer = PrintPooler.obtainPrinter(); printer.print();

2. Imbunatatiti clasa de mai sus astfel: a. Primul apel obtainPrinter creaza si un fir (Thread) care din 10 in 10 secunde verifica daca sunt printere obtinute si neutilizate. In acest caz le pune la dispozitie altor client. b. Realizati o interfata de monitorizare a PrintPooler-ului. In aceasta interfata se va vedea sta

INGINERIA PROGRAMRII. ndrumar de laborator

119

13 BUILDER
13.1 INTENTIE (CU CE SCOP)
Acest sablon are ca scop separarea constructiei unui obiect de reprezentarea acestuia. Prin aceasta separare devine posibila folosirea aceluiasi process de constructie pentru mai multe reprezentari. Cu alte cuvinte, algoritmul ce construieste obiectul complex in cauza, nu tine cont de reprezentare (reprezentarea fiind pugin-abila).

13.2 MOTIVATIE (DE CE SE FOLOSESTE)


Un reader pentru documente RTF (Rich Text Format) se doreste a fi capabil sa converteasca RTF la diverse formate (ASCII, TeX, HTML, .) sau chiar sa faca ceva absolut diferit si anume sa creeze o componenta grafica (un element de interfata complex) ce permite utilizatorului vizualizarea / editarea textului formatat. Ar fi de dorit ca acel reader sa poata fi folosit si in conversii la alte tipuri de documente si deasemenea, editorul sa poate edita si alte documente decat RTF (schimband doar readerul). Principial, ceea ce se doreste este sintetizat in imaginea de mai jos:

INGINERIA PROGRAMRII. ndrumar de laborator

120

Document RTF RTF Reader

ASCII

TeX

Test rosu Albastru italic VERDE BOLD

Intr-o abordare monolitica (nemodulara), ar trebui facute mai multe readere separate chiar daca procesul de creare a documentului sau produsului rezultat este acelasi. Cele trei readere vor avea presarate prin codul lor sursa elemente de formare/reprezentare ale produsului de iesire. Aceasta abordare are o multime de deficiente printre care: modificarea algoritmului de creare este foarte dificila. Pe cazul dat trebuiesc facute modificari in cel putin trei locuri. modificarea reprezentarii este deasemenea greoaie intrucat readerul este cuplat cu modulul de creare a partilor. O implementare bazate pe sablonul de proiectare Builder, rezolva ambele probleme mai sus mentionate. Fiecare conversie + generarea componentei complexe se realizeaza cu cate o implementare a interfetei AbstractBuilder. Acest pattern se bazeaza pe faptul ca intregul este construit intotdeauna din parti iar construirea partilor este un detaliu de implementare incapsulat in Builderul concret specific produsului. Crearea

INGINERIA PROGRAMRII. ndrumar de laborator

121

intregului se face pas cu pas, fiecare metoda specificata in intefata abstracta Builder contrubuind cu ceva (cu o parte) la produsul finit. Pe exemplul dat in aceste randuri, RTFReaderul (cu rol de Director), este responsabil cu citirea/intelegerea documentului RTF si pe masura ce acesta gaseste instructiuni de formatare sau texte, le directioneaza ca apeluri builderului (setat de catre client sau aflat prin intermediul unui factory). Toate aceste apeluri sunt facute prin intermediul interfetei Builder, Directorul fiind astfel izolat de implementarile ASCIIBuilder, TeXBuilder, s.a.m.d.

13.3 APLICABILITATE (CAND IL APLICAM)


Builder se foloseste cand: algoritmul de creare al unui obiect complex (un composite de exemplu) trebuie se fie independent de partile ce il formeaza si de modul in care acestea sunt asamblate procesul de constructie trebuie sa permita reprezentari diferite pentru obiectul creat

13.4 STRUCTURA

INGINERIA PROGRAMRII. ndrumar de laborator

122

13.5 PARTICIPANTI
13.5.1 BUILDER (TEXTCONVERTOR)
Specifica o interfata pentru crearea partilor componente ale unui produs.

13.5.2 CONCRETEBUILDER (ASCII CONVERTOR)


construieste si asambleaza parti ale produsului concret la ordinele Directorului defineste si este raspunzator de reprezentarea pe care o creaza pune la dispozitie o interfata pentru luarea produsului rezultat (o metoda getResult sau getAsciiText sau getTextWidget).

13.5.3 DIRECTOR (RTFREADER)


construieste obiectul complex folosind interfata abstracta Builder

13.5.4 PRODUCT (ASCIITEXT, TEXTEXT, TEXTCOMPONENT)


reprezinta obiectul de construit ConcreteBuilder construieste reprezentarea interna a produsului si defineste procesul prin care el este asamblat. Include clase care definesc partile constituente ale produsului finit.

13.6 INTERACTIUNE (COLABORARI


existent sau creat.

SI COLABORATORI)

Clientul creaza obiectul director si il configureaza cu un builder concret in prealabil

Directorul notifica builderul de cate ori o parte a produsului trbuie create. Builderul primeste cereri de la director si adauga partile specificate la produsul complex. Clientul are acum acces la prdusul finit. Toate aceste interactiuni sunt pezentate in diagrama de secventa de mai jos.

INGINERIA PROGRAMRII. ndrumar de laborator

123

13.7 CONSECINTE
Reprezentarea interna a produsului poate sa varieze. Builderul este cunoscut de catre director doar prin intermediul interfetei Builderului abstract (TextBuilder sau HamburgerBuilder din sectiunea Implementare de mai jos). Daca reprezentarea interna a produsului se schimba se poate defini un alt builder extinzand builderul abstract. Se izoleaza codul de constructie de cel de reprezentare. Se imbunatateste modularitatea incapsulandu-se modul in care obiectul este construit si reprezentat. Builderul concret este singurul care stie cum se creaza / reprezinta un produs particular iar codul odata scris poate fi folosit de catre mai multi Directori. Pe exemplul cu RTFReaderul, s-ar putea scrie un alt director care sa cunoasca sintaxa HTML, rezultatul fiind un convertor HTML -> TeX sau chiar o componenta editor de HTML.

INGINERIA PROGRAMRII. ndrumar de laborator

124

Da un grad mai mare de control procesului de constructie. Spre deosebire de paternurile creationale care construiesc produsele dintr-un singur foc, Builder construieste produsul pas cu pas sub privirea directorului (sub controlul acestuia).

13.8 IMPLEMENTARE
Clasa Builder trebuie sa defineasca cate o operatie pentru fiecare componenta pe care un director ar putea sa o creeze. Builderul abstract nu este de fapt o interfata ci o clasa oarba cu toate metodele implementate intr-un mod implicit (nu fac nimic) astfel fiind posibil ca un Builder concret sa suprascrie doar metodele ce-l intereseaza. Nu se poate gasi o clasa abstracta de produse intrucat spre deosebire de AbstractFactory produsele variaza foarte mult (de fapt pot chiar san nu aiba nimic in comun). Spre exemplificare, ce poate avea in comun un fisier ASCII text cu o componente grafica de editare de documente HTML? Dealtfel nici nu este necesar, in acest caz clientul stiind intotdeauna ce builder are directorul setat. Stie acest lucru pentru ca chiar el (cleintul) a creat Bulderul concret si i l-a furnizat Directorului inspre folosinta.

13.8.1 EXEMPLU RESTAURANT


Un meniu pentru copii este format dintr-un produs principal (hamburger), o garnitura (cartofi prajiti), un suc (fanta) si o jucarie (o masinuta). Pot sa existe abateri de la meniul de baza dar principiul de constructie este acelasi. Indiferent daca clientul doreste un hamburger, un cheeseburger, sau un sandwich de pui, precesul este similar: Angajatul de la casa spune bucatarului sa faca partile necesare unui meniu (meniul principal, garniture, bautura, jucarie) apoi la impacheteaza (nu si bautura care e lasata in afara pachetului) si le serveste clientului. Procesul poate fi util si in alte restaurante.

INGINERIA PROGRAMRII. ndrumar de laborator

125

public class Casier { private CreatorMeniu builder;

public void creareMeniu() { contribuieCuMeniuPrincipal(); contribuieCuBautura(); contribuieCuJucarie(); contribuieCuGarnitura(); }

INGINERIA PROGRAMRII. ndrumar de laborator

126

public class CreatorMeniu { public void contribuieCuMeniuPrincipal() { }

public void contribuieCuBautura() { }

public void contribuieCuJucarie() { }

public void contribuieCuGarnitura() { }

public class HamburgerBuilder extends CreatorMeniu { Hamburger h = new MeniuHamburger(); public void contribuieCuMeniuPrincipal() {

INGINERIA PROGRAMRII. ndrumar de laborator

127

h.setCarne(porc); }

public void contribuieCuBautura() { h.setBautura(new Fanta()); }

public void contribuieCuJucarie() { }

public void getHamburgerCreat() { return h; }

Un anumit tip specific de CreatorMeniu ar putea avea anumite metode lasate goale (contribuieCuJucarie) sau chiar inexistente (dar mostenite goale de la parinte), aceasta insemnand ca HamburgerBuilder nu ofera cele doua componente in oferta. Produsele create de implementari CreatorMeniu ar putea fi atat de diferite incat nu se pot pune sub aceeasi interfata. Un exemplu ar fi un restaurant in care clientul poate vedea o holograma a produsului ce doreste sa-l consume. Generatorul acestei holograme nu este decat o extensie a interfetei MeniuCreator de mai sus. Cod sursa RTFReader

INGINERIA PROGRAMRII. ndrumar de laborator

128

class RTF_Reader { TextConverter builder; String RTF_Text;

public RTF_Reader( TextConverter aBuilder, String RTFtoConvert ) { builder = aBuilder; RTF_Text = RTFtoConvert; }

public void parseRTF() { RTFTokenizer rtf = new RTFTokenizer( RTF_Text );

while ( rtf.hasMoreTokens() ) { RTFToken next = rtf.nextToken();

switch ( next.type() ) { case CHAR: break; case FONT: case PARA: etc. } builder.font( next.font() ); break; builder.newParagraph( ); break; builder.character( next.char() );

INGINERIA PROGRAMRII. ndrumar de laborator

129

} } }

abstract class TextConverter { public void character( char nextChar ) { public void font( Font newFont ) public void newParagraph() {} } { } }

class ASCII_Converter extends TextConverter { StringBuffer convertedText = new StringBuffer();

public void character( char nextChar ) { convertedText.append( nextChar ); }

public String getText() { return convertedText.toString(); } }

class TeX_Converter extends TextConverter

INGINERIA PROGRAMRII. ndrumar de laborator

130

{ public void character( char nextChar ) public void font( Font newFont ) public void newParagraph() public TeX getText() } { blah }

{ blah } { blah }

{ return the correct thing }

main() { ASCII_Converter simplerText = new ASCII_Converter(); String rtfText;

// read a file of rtf into rtfText

RTF_Reader myReader = new RTF_Reader( simplerText, rtfText );

myReader.parseRTF();

String myProduct = simplerText.getText(); }

13.9 PROBLEMA PROPUSA


Sa se creeze un program Java care sa aplice sablonul Builder pentru o societate ce construieste locuinte. Se stie ca aceasta societate poate moderniza apartamente si poate construi case si duplexuri. Procesul de constructie/modernizare este in mai multi pasi ce se pot formaliza astfel:

INGINERIA PROGRAMRII. ndrumar de laborator

131

construireFundatie -> ridicareZiduri -> executieAcoperis -> instalatieElectrica -> instalatieSanitara -> executareTencuiala -> finisajCuRigips -> modernizareCurte. Creati toate clasele aferente problemei fi faceti o clasa de test ce instantiaza societatea comerciala ce va moderniza un apartament.

INGINERIA PROGRAMRII. ndrumar de laborator

132

14 ALTE CATEVA SABLOANE


14.1 ADAPTER
14.1.1 SCOPUL
Convertete interfaa unei clase n alta interfata, ceruta de client. Adapterul las clasele s lucreze mpreun cand sunt probleme datorate incompatibilitii interfeelor.

a) Adaptarea de clasa cu mostenire multipla (Java nu permite) b) Adaptarea obiect nu necesita mostenire multipla: se rezolva prin delegare

14.2 BRIDGE
14.2.1 SCOPUL
Separ abstractizarea de implementare astfel nct acestea se pot modifica independent.

INGINERIA PROGRAMRII. ndrumar de laborator

133

14.3 COMPOSITE
dorii s reprezentai o ntreag ierarhie de obiecte. dorii ca clienii s ignore diferena dintre obiectele compuse i obiectele individuale. Clienii vor trata toate obiectele din structura compus uniform.

14.3.1 STRUCTURA

INGINERIA PROGRAMRII. ndrumar de laborator

134

14.3.2 PARTICIPANI
Component (Grafic) Declar interfaa pentru obiectele compuse Declar o interfa pentru accesarea i maparea componentelor copil Definete o interfa pentru accesarea componentelor printe ntr-o structur recursiv Leaf (Rectangle, Line, Text, etc.) reprezint obiectele frunz.

Composite (Picture) Definete comportamentul pentru componentele care au copii Memoreaz componentele copil

Client Manipuleaz obiectele

INGINERIA PROGRAMRII. ndrumar de laborator

135

14.4 DECORATOR
14.4.1 SCOPUL
Ataeaz dinamic responsabiliti unui obiect. Decorator furnizeaz o alternativ flexibil subclaselor pentru extinderea funcionaliti.

14.4.2 PARTICIPANI
Component: definete interfaa pentru obiectele crora li se pot aduga funciuni in mod dinamic; ConcreteComponent: definete un obiect concret cruia i se pot aduga funciuni; Decorator: conine o referina la Component (compref) si definete o interfaa conforma cu cea a lui Component; ConcreteDecorator: aduga funciuni noi unei componente.

INGINERIA PROGRAMRII. ndrumar de laborator

136

15 BIBLIOGRAFIE
Alistair Cockburn - Writing Effective Use Cases, Addison-Wesley, 2001 David Eriksson - Designing an object-oriented decompiler. Decompilation support for Interactive Disassembler Pro, Master Thesis in Software Engineering, Thesis no: MSE-2002:17, June 2002 (source Internet) Kent Beck, Martin Fowler - Planning Extreme Programming, Addison Wesley, 2000 Anneke Kleppe, Jos Warmer, Wim Bast - MDA Explained: The Model Driven Architecture: Practice and Promise, Addison Wesley, 2003 Sherif M. Yacoub, Hany H. Ammar - Pattern-Oriented Analysis and Design: Composing Patterns to Design Software Systems, Addison Wesley, 2003 Martin Fowler UML Distilled Second Edition: A Brief Guide to the Standard Object Modeling Language, Addison Wesley, 1999 Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides Elements of Reusable Object-Oriented Software, Addison Wesley, 1995 Martin Robert Object-Oriented Design Principle - www.objectmentor.com, 2002 Dorin Sima Elemente de inginerie software, Ed. ULBS, 2003 http://hillside.net/patterns/ http://www.extremeprogramming.com/ http://martinfowler.com/ http://www.gentleware.com, Poseidon Site, 2007 http://www.eclipse.org, Eclipse - an open development platform, 2007

S-ar putea să vă placă și