You are on page 1of 266

Cuprins

Capitolul 1. Compilarea, decompilarea i obscurizarea programelor C#


1. Obiective ............................................................................................................................... 9 2. Structura general a unui program C# ...................................................................10 2.1. Clase ............................................................................................................................10 2.2. Clase statice i membri statici ..........................................................................11 2.3. Cmpuri constante ................................................................................................13 2.4. Structuri ....................................................................................................................14 2.5. Trimiterea argumentelor prin referin ......................................................16 2.6. Operaiile de boxing i unboxing .....................................................................16 2.7. Enumeraii ................................................................................................................17 3. Compilarea, decompilarea i obscurizarea codului ..........................................18 3.1. Compilarea. Limbajul Intermediar Comun .................................................18 3.2. Decompilarea. Programul .NET Reflector ....................................................19 3.3. Compilarea n modurile Debug i Release ...................................................23 3.4. Obscurizarea codului. Dotfuscator .................................................................29 4. Aplicaii................................................................................................................................30

Capitolul 2. Stilul de scriere a codului. Tratarea excepiilor. Interfaa grafic cu utilizatorul


1. Obiective .............................................................................................................................35 2. Stilul de scriere a codului .............................................................................................35 2.1. Acoladele ...................................................................................................................36 2.2. Standarde de programare ..................................................................................37 2.3. Convenii pentru nume .......................................................................................39 3. Tratarea excepiilor ........................................................................................................42 3.1. Tratarea excepiilor pe firul de execuie al aplicaiei .............................46 4. Interfaa cu utilizatorul .................................................................................................47 4.1. Proiectarea comenzilor i interaciunilor ...................................................47 4.2. Considerente practice ..........................................................................................48 4.3. Profilurile utilizatorilor ......................................................................................50 5. Interfaa grafic cu utilizatorul n Microsoft Visual Studio .NET .................51 6. Elemente de C# ................................................................................................................58 6.1. Clase pariale ...........................................................................................................58 6.2. Proprieti. Accesori.............................................................................................59 6.2.1. Accesorul get .................................................................................................60 6.2.2. Accesorul set ..................................................................................................61
3
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

6.2.3. Aspecte mai complexe ale lucrului cu proprieti ................................62 7. Aplicaii................................................................................................................................65

Capitolul 3. Reutilizarea codului cu ajutorul DLL-urilor


1. Obiective .............................................................................................................................69 2. Bibliotecile legate dinamic ..........................................................................................69 3. Crearea DLL-urilor n C# ..............................................................................................70 3.1. Legarea static ........................................................................................................72 3.2. Legarea dinamic...................................................................................................72 3.3. Depanarea unui DLL.............................................................................................74 4. Grafic n C# ......................................................................................................................75 5. Aplicaii................................................................................................................................77

Capitolul 4. Documentarea unui proiect. Fiiere de ajutor


1. Obiective .............................................................................................................................81 2. Crearea de fiiere de ajutor .........................................................................................81 2.1. Crearea de fiiere HLP .........................................................................................81 2.2. Crearea de fiiere CHM........................................................................................86 3. Activarea unui fiier de ajutor prin program.......................................................88 3.1. Process.Start.............................................................................................................88 3.2. HelpProvider ...........................................................................................................88 3.3. Help..............................................................................................................................89 4. Generarea automat a documentaiei API ............................................................90 5. Comentariile ......................................................................................................................92 6. Lucrul cu fiiere n C#: ncrcare, salvare .............................................................95 7. Aplicaii................................................................................................................................96

Capitolul 5. Diagrame UML


1. Obiective .......................................................................................................................... 105 2. Diagrame principale ale UML .................................................................................. 105 2.1. Diagrama cazurilor de utilizare .................................................................... 105 2.2. Diagrama de clase............................................................................................... 107 2.2.1. Dependena ................................................................................................. 107 2.2.2. Asocierea ...................................................................................................... 108 2.2.3. Agregarea i compunerea ..................................................................... 110 2.2.4. Motenirea................................................................................................... 110 2.2.5. Metode abstracte i virtuale................................................................. 112 2.2.6. Interfee ........................................................................................................ 113 2.2.7. Trsturi statice ........................................................................................ 113 2.3. Diagrame de activiti....................................................................................... 114 2.4. Diagrama de secvene ....................................................................................... 117 3. Altova UModel ................................................................................................................ 118
4
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

3.1. Diagrama de clase............................................................................................... 119 3.1.1. Generarea de cod ......................................................................................... 120 3.1.2. Crearea diagramei unui proiect existent ........................................... 125 3.1.3. Aranjarea automat a elementelor din diagrame .......................... 128 3.2. Celelalte diagrame.............................................................................................. 128 4. Aplicaii............................................................................................................................. 128

Capitolul 6. Arhitectura MVC


1. Obiective ........................................................................................................................... 131

2. Introducere. Arhitectura cu trei straturi ............................................................ 131 3. Arhitectura MVC ............................................................................................................ 133 4. Arhitectura MVP............................................................................................................ 135 4.1. Variante de actualizare a Vizualizrii......................................................... 136 5. Aplicaii............................................................................................................................. 138

Capitolul 7. ablonul de proiectare Metoda Fabric


1. Obiective .......................................................................................................................... 151 2. ablonul creaional Metoda Fabric ..................................................................... 151 3. Exemplu de implementare ....................................................................................... 152 4. Motenirea i polimorfismul.................................................................................... 154 4.1. Polimorfismul ...................................................................................................... 154 4.2. Clase abstracte ..................................................................................................... 154 4.3. Interfee .................................................................................................................. 155 4.4. Membri virtuali ................................................................................................... 156 4.5. Clase sigilate i membri sigilai .................................................................... 158 4.6. nlocuirea unui membru cu ajutorul cuvntului cheie new .............. 159 4.7. Accesarea clasei de baz cu ajutorul cuvntului cheie base ............. 160 5. Aplicaii............................................................................................................................. 161

Capitolul 8. abloanele de proiectare Singleton i Prototip


1. Obiective .......................................................................................................................... 167 2. ablonul creaional Singleton .................................................................................. 167 2.1. Exemplu de implementare ............................................................................. 168 3. ablonul creaional Prototip .................................................................................... 169 3.1. Exemplu de implementare ............................................................................. 170 4. Aplicaii............................................................................................................................. 172

Capitolul 9. ablonul de proiectare Faad


1. Obiectiv ............................................................................................................................. 185 2. Scop i motivaie ........................................................................................................... 185 3. Aplicabilitate .................................................................................................................. 186 4. Analiza ablonului ........................................................................................................ 187
5
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

5. Exemplu de implementare ....................................................................................... 188 6. Aplicaie............................................................................................................................ 190

Capitolul 10. ablonul de proiectare Proxy


1. Obiectiv ............................................................................................................................. 193 2. Scop i motivaie ........................................................................................................... 193 3. Aplicabilitate .................................................................................................................. 194 4. Analiza ablonului ........................................................................................................ 195 5. Exemplu de implementare ....................................................................................... 196 6. Aplicaii............................................................................................................................. 197

Capitolul 11. ablonul de proiectare Comand


1. Obiective .......................................................................................................................... 211 2. Scop i motivaie ........................................................................................................... 211 3. Aplicabilitate .................................................................................................................. 214 4. Analiza ablonului ........................................................................................................ 215 5. Exemplu de implementare ....................................................................................... 216 6. Aplicaie............................................................................................................................ 218

Capitolul 12. Evaluarea vitezei de execuie a unui program


1. Obiective .......................................................................................................................... 231 2. Metoda DateTime.......................................................................................................... 231 3. Pointeri n C# ................................................................................................................. 232 4. Metoda PerformanceCounter ................................................................................... 234 4.1. Metode de accelerare ........................................................................................ 235 5. Metoda Stopwatch ........................................................................................................ 236 6. Compilarea JIT ............................................................................................................... 236 7. Aplicaii............................................................................................................................. 238

Capitolul 13. Testarea unitilor cu NUnit


1. Obiectiv ............................................................................................................................. 243 2. Testarea unitilor ....................................................................................................... 243 3. Utilizarea platformei NUnit ...................................................................................... 244 4. Aplicaii............................................................................................................................. 249

Capitolul 14. Rapoarte de testare


1. Obiective .......................................................................................................................... 253 2. Testarea unei ierarhii de clase ................................................................................ 253 3. Aplicaie............................................................................................................................ 256

Referine .................................................................................................................... 263


6
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Cuvnt nainte
n anul 2001 am nceput s predau laboratoarele de Ingineria programrii la Facultatea de Automatic i Calculatoare de la Universitatea Tehnic Gheorghe Asachi din Iai. La acel moment, n unele faculti de profil din Romnia, aceste laboratoare se concentrau pe programare vizual Windows, astfel nct n primii ani coninutul s-a axat pe programare folosind Borland C++ Builder i Microsoft Visual Studio cu Microsoft Foundation Classes (MFC). Pe lng aspectele de programare vizual, am prezentat nc de pe atunci chestiuni legate de modularizare, utilizarea DLL-urilor, crearea aplicaiilor COM, tratarea excepiilor, realizarea de fiiere de ajutor (help), diagrame UML i evaluarea vitezei de execuie a programelor. n anul 2003 am introdus limbajul C# pentru partea de programare a laboratoarelor, limbaj de care m-am ataat nc de la apariia sa, n 2002, i pe care am continuat s l utilizez de atunci pentru toate proiectele de programare de natur profesional sau personal. Din 2008, odat cu rescrierea cursurilor de Ingineria programrii, am modificat i laboratoarele, adugnd o parte substanial legat de proiectarea i testarea aplicaiilor. Astfel, un laborator trateaz abloane arhitecturale, cinci se refer la abloane de proiectare i dou la testarea unitilor. Laboratoarele, n forma lor actual, constituie rezultatul experienei acumulate n timp, ncercnd s ofer o viziune practic asupra problemelor complexe legate de realizarea produselor software comerciale. Sunt recunosctor tuturor studenilor pentru semnalarea neclaritilor i erorilor strecurate n laboratoare. De asemenea, mulumesc studenilor Veridiana Mrtic, Simona Scripcaru, Liudmila Tofan, Florin Alexandru Hodorogea i Alexandru Gologan pentru observaiile asupra versiunii preliminare a acestui ghid.

7
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

8
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 1

Compilarea, decompilarea i obscurizarea programelor C#


1. Obiective 2. Structura general a unui program C# 3. Compilarea, decompilarea i obscurizarea codului 4. Aplicaii

1. Obiective
Aplicaiile de ingineria programrii nu se doresc a fi, n primul rnd, aplicaii de programare n C#. Din pcate, programe complexe la standarde comerciale nu se pot termina n dou ore, deci problemele vor avea o natur academic surprinznd ns chestiuni ce se pot regsi n aplicaiile din industrie i care trebuie rezolvate n principal la standarde nalte de calitate. Accentul principal al prezentului ghid cade pe proiectarea programelor, folosind de exemplu abloane de proiectare, pe modul cum se gndete i se scrie un program, pe testare i pe crearea diverselor tipuri de documente aferente. Vom utiliza limbajul C# pentru c este un limbaj modern, special destinat dezvoltrii rapide de aplicaii. Cnd vom considera necesar, vom prezenta i noiuni de programare n C#, mai ales n primele trei capitole. Ca mediu de dezvoltare, vom ntrebuina Microsoft Visual Studio 2005. Obiectivele primului capitol sunt urmtoarele: 1. Prezentarea modului de organizare a unui program C# care conine clase, structuri i enumeraii. Discutarea diferenelor dintre tipurile referin (clase) i tipurile valoare (structuri); 2. Precizarea diferenelor de compilare n modurile Debug i Release; 3. Descrierea posibilitilor de decompilare a aplicaiilor .NET i de protejare a acestora prin obscurizarea codului.

9
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

2. Structura general a unui program C#


O soluie C# const dintr-unul sau mai multe proiecte. Proiectele constau dintr-unul sau mai multe fiiere. Fiierele pot conine zero sau mai multe spaii de nume (engl. namespaces). Un namespace poate conine tipuri precum clase, structuri, enumeraii, dar i alte namespace-uri. Mai jos este prezentat un schelet al unui program C# alctuit din aceste elemente.
using System; namespace MyNamespace { class MyClass { } struct MyStruct { } enum MyEnum { } class MyMainClass { static void Main(string[] args) { // nceputul programului propriu-zis } } }

2.1. Clase
Clasa este cel mai important tip de date n C#. n urmtorul exemplu, se definete o clas public avnd un cmp, o metod i un constructor. De remarcat terminologia utilizat pentru o variabil membru, cmp, deoarece termenul proprietate reprezint un alt concept C# pe care l vom discuta n capitolul 2.

10
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 1. Compilarea, decompilarea i obscurizarea programelor C#

n exemplul de mai jos, problema este definirea unui cmp public. Conform teoriei programrii orientate obiect, toate cmpurile trebuie s fie private iar accesul la ele s se fac prin metode publice.
public class Person { // Cmp / Field public string name; // Constructor public Person() { name = "nedefinit"; } // Metod / Method public void ChangeName(string newName) { name = newName; } } class TestPerson { static void Main() { Person person1 = new Person(); Console.WriteLine(person1.name); person1.ChangeName("Ion Popescu"); Console.WriteLine(person1.name); } }

// !!! cmp public, nerecomandat

2.2. Clase statice i membri statici


O clas static nu poate fi instaniat. Deoarece nu exist instane ale clasei, apelarea unei metode dintr-o clas static se realizeaz folosind numele clasei nsei. De exemplu, dac avem o clas static numit UtilityClass care conine o metod public numit MethodA, aceasta este apelat n modul urmtor:
UtilityClass.MethodA(); 11
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

O clas static poate fi utilizat ca o modalitate convenabil de a grupa o serie de metode care opereaz asupra unor parametri de intrare i nu au nevoie de cmpuri ntruct nu au stare intern. De exemplu, n mediul .NET, clasa static System.Math conine metode care realizeaz operaii matematice, fr a avea nevoie s memoreze sau s acceseze alte date n afara argumentelor cu care sunt apelate. Mai jos este prezentat un exemplu de clas static avnd dou metode care convertesc temperatura din grade Celsius n grade Fahrenheit i viceversa.
public static class TemperatureConverter { public static double CelsiusToFahrenheit(string temperatureCelsius) { // conversia argumentului din string n double double celsius = Convert.ToDouble(temperatureCelsius); // conversia din grade Celsius n grade Fahrenheit double fahrenheit = (celsius * 9 / 5) + 32; return fahrenheit; } public static double FahrenheitToCelsius(string temperatureFahrenheit) { double fahrenheit = Convert.ToDouble(temperatureFahrenheit); double celsius = (fahrenheit 32) * 5 / 9; return celsius; } } class TestTemperatureConverter { static void Main() { Console.WriteLine("Selectati directia de conversie"); Console.WriteLine("1. Din grade Celsius in grade Fahrenheit"); Console.WriteLine("2. Din grade Fahrenheit in grade Celsius"); Console.Write(":"); string selection = Console.ReadLine(); double f, c = 0;

12
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 1. Compilarea, decompilarea i obscurizarea programelor C# switch (selection) { case "1": Console.Write("Introduceti temperatura in grade Celsius: "); f = TemperatureConverter.CelsiusToFahrenheit(Console.ReadLine()); // se afieaz rezultatul cu 2 zecimale Console.WriteLine("Temperatura in grade Fahrenheit: {0:F2}", f); break; case "2": Console.Write("Introduceti temperatura in grade Fahrenheit: "); c = TemperatureConverter.FahrenheitToCelsius(Console.ReadLine()); Console.WriteLine("Temperatura in grade Celsius: {0:F2}", c); break; default: Console.WriteLine("Selectati un tip de conversie"); break; } // ateapt apsarea tastei ENTER Console.ReadLine(); } }

Deseori, se utilizeaz clase nestatice cu membri statici n locul claselor statice. n acest caz, membrii statici pot fi apelai chiar i naintea crerii unor instane ale clasei. La fel ca mai sus, membrii statici sunt accesai cu numele clasei, nu al unei instane. Indiferent cte instane ale clasei sunt create, pentru un membru static exist ntotdeauna o singur copie. Metodele statice nu pot accesa metode i cmpuri nestatice din clas. Cmpurile statice se folosesc n general pentru a stoca valori care trebuie cunoscute de ctre toate instanele clasei i pentru a pstra evidena numrului de obiecte care au fost instaniate.

2.3. Cmpuri constante


Un cmp constant este static n comportament (nu poate fi modificat) i de aceea aparine tot tipului i nu instanelor. Prin urmare va fi accesat tot cu numele clasei, ca i cmpurile statice.

13
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C# public class Car { public const int NumberOfWheels = 4; public static void Drive() { } // alte cmpuri i metode nestatice }

// utilizare din exteriorul clasei Car.Drive(); int i = Car.NumberOfWheels;

2.4. Structuri
n C#, structurile sunt versiuni simplificate ale claselor. De obicei, ele ocup mai puin spaiu n memorie i sunt potrivite pentru tipurile de date de dimensiuni mici, utilizate frecvent. Diferena cea mai important ntre structuri i clase este faptul c structurile sunt tipuri valoare iar clasele sunt tipuri referin. Cnd se creeaz o instan de tip valoare, se aloc n memoria stiv un singur spaiu pentru pstrarea valorii instanei respective. n acest mod sunt tratate tipurile primitive precum int, float, bool, char etc. Compilatorul creeaz automat un constructor implicit care iniializeaz toate cmpurile cu valorile implicite ale tipurilor acestora, de exemplu tipurile numerice cu 0, bool cu false, char cu '\0' iar cmpurile de tip referin (instane ale altor clase) cu null. Pentru structuri nu se poate declara un constructor implicit (fr parametri), ns se pot declara constructori cu parametri, care s iniializeze membrii cu valori diferite de cele implicite. Dezalocarea instanelor se face automat cnd acestea ies din domeniul lor de definiie. La alocarea instanelor de tip referin, se memoreaz att referina obiectului n stiv, ct i spaiul pentru coninutul obiectului n heap. Managementul memoriei este fcut de ctre garbage collector. S considerm urmtoarea situaie: structura MyPoint i clasa MyForm.
MyPoint p1; p1 = new MyPoint(); MyForm f1; f1 = new MyForm(); // p1 este alocat cu valorile implicite ale membrilor // nu are efect aici, reseteaz valorile membrilor // se aloc referina, f1 = null // se aloc obiectul, f1 primete referina acestuia

14
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 1. Compilarea, decompilarea i obscurizarea programelor C#

n primul caz, se aloc un singur spaiu n memorie pentru p1. n al doilea caz, se aloc dou spaii: unul pentru obiectul MyForm i unul pentru referina lui, f1. De aceea, dac vrem s declarm un vector de 1000 de puncte, este mai avantajos s crem o structur dect o clas, deoarece astfel vom aloca mai puin memorie. Dac vrem s copiem obiectele:
MyPoint p2 = p1; MyForm f2 = f1;

p2 devine o copie independent a lui p1, fiecare cu cmpurile lui separate. n cazul lui f2, se copiaz numai referina, astfel nct f1 i f2 pointeaz ctre acelai obiect. Fie metoda urmtoare, apelat cu argumentele p1 i f1: Change(p1, f1):
void Change(MyPoint p, MyForm f) { p.X = 10; // p este o copie, instruciunea nu are efect asupra lui p1 f.Text = "Hello"; // f i f1 pointeaz la acelai obiect, f1.Text se schimb f = null; // f este o copie a referinei f1, instruciunea nu are efect asupra lui f1 }

Pentru o compatibilitate ct mai bun cu mediul .NET, Biblioteca MSDN recomand utilizarea structurilor numai n urmtoarele situaii: Tipul reprezint o valoare unitar, similar cu un tip primitiv (int, double etc.); Dimensiunea unei instane este mai mic de 16 octei (deoarece la transmiterea ca parametru n metode se creeaz o nou copie pe stiv); Tipul este immutable (metodele nu modific valorile cmpurilor; cnd se dorete schimbarea acestora se creeaz un nou obiect cu noile valori); Operaiile de boxing (mpachetare) i unboxing (despachetare), prezentate n seciunea 2.6, sunt rare.

15
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

2.5. Trimiterea argumentelor prin referin


Trimiterea argumentelor prin referin se realizeaz cu ajutorul cuvintelor cheie ref i out. Astfel, modificrile fcute asupra parametrului n metoda apelat se vor reflecta asupra variabilei din metoda apelant. Un argument trimis ca ref trebuie iniializat mai nti. Un argument trimis cu out nu trebuie iniializat n metoda apelant, ns metoda apelat este obligat s i atribuie o valoare.
class RefExample { static void Method(ref int i) { i = 44; } static void Main() { int val = 0; Method(ref val); // val este acum 44 } } class OutExample { static void Method(out int i) { i = 44; } static void Main() { int val; Method(out val); // val este acum 44 } }

Revenind la exemplul cu structura MyPoint i clasa MyForm, fie metoda urmtoare, apelat cu argumentele p1 i f1: Change(ref p1, ref f1):
void Change(ref MyPoint p, ref MyForm f) { p.X = 10; // se modific p1.X f.Text = "Hello"; // se modific f1.Text f = null; // f1 este distrus }

2.6. Operaiile de boxing i unboxing


Aceste operaii permit ca tipurile valoare s fie tratate drept tipuri referin, dup cum se poate vedea n figura 1.1.

16
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 1. Compilarea, decompilarea i obscurizarea programelor C#

Boxing (mpachetare)
int i = 123; object o = i; // tip valoare // tip referin (boxing)

Unboxing (despachetare)
int i = 123; object o = i; int j = (int)o;

// tip valoare (unboxing)

Figura 1.1. Operaiile de boxing i unboxing

Vom utiliza aceste operaii n capitolul 3.

2.7. Enumeraii
O enumeraie este alctuit dintr-o mulime de constante. Enumeraiile pot avea orice tip integral cu excepia lui char, tipul implicit fiind int. Valoarea implicit a primului element este 0, iar valorile succesive sunt incrementate cu 1. De exemplu:
enum Days { Sun, Mon, Tue, Wed, Thu, Fri, Sat };

n aceast enumeraie, Sun este 0, Mon este 1, Tue este 2 i aa mai departe. Enumeratorii pot avea iniializatori care suprascriu valorile implicite. De exemplu:
enum Zile { Lun = 1, Mar, Mie, Joi, Vin, Sam, Dum };

Aici secvena de elemente pornete de la 1 n loc de 0. Urmtoarele instruciuni sunt valide:

17
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C# int x = (int)Zile.Lun; Zile z1 = Zile.Mar; Zile z2 = (Zile)3; string s = z2.ToString(); // x = 1 // z1 = Mar // z2 = Mie // s = "Mie"

Modificarea valorilor unei enumeraii ntr-o nou versiune a unui program poate cauza probleme pentru alte programe ce folosesc codul respectiv. De multe ori valorile din enum sunt utilizate n instruciuni switch, iar dac noi elemente sunt adugate enumeraiei, se va activa cazul default. Dac ali dezvoltatori depind de acel cod, ei trebuie s tie cum s trateze noile elemente adugate.

3. Compilarea, decompilarea i obscurizarea codului


3.1. Compilarea. Limbajul Intermediar Comun
Limbajul Intermediar Comun (engl. Common Intermediate Language, CIL), cunoscut i sub denumirea de Limbajul Intermediar Microsoft (engl. Microsoft Intermediate Language, MSIL) este limbajul de nivelul cel mai sczut al platformei .NET. MSIL a fost numele utilizat pentru limbajul intermediar pn la versiunea 1.1 a platformei .NET. ncepnd cu versiunea 2.0, limbajul a fost standardizat iar denumirea standardului este CIL. Compilarea i execuia unui program .NET se realizeaz n dou etape, dup cum se prezint n figura 1.2.

Figura 1.2. Etapele compilrii i execuiei unui program .NET


18
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 1. Compilarea, decompilarea i obscurizarea programelor C#

n timpul compilrii limbajelor .NET, codul surs este transformat n cod CIL i nu direct n cod executabil de ctre procesor. CIL reprezint un set de instruciuni independent de sistemul de operare i de procesor, care poate fi executat n orice mediu pe care este instalat platforma .NET, de exemplu motorul de execuie (runtime-ul) .NET pentru Windows, sau Mono pentru Linux. Compilarea la timp (engl. just-in-time compilation, JIT) are loc n momentul execuiei efective a programului i presupune transformarea codului CIL n instruciuni executabile imediat de ctre procesor. Conversia se realizeaz gradat n timpul execuiei programului, iar compilatorul JIT efectueaz o serie de optimizri specifice mediului de execuie. Avantajul principal al platformei .NET este interoperabilitatea dintre diferite limbaje de programare. De exemplu, un proiect scris n Visual Basic poate fi apelat fr modificri dintr-un proiect C#.

3.2. Decompilarea. Programul .NET Reflector


Deoarece codul intermediar este standardizat, este relativ simpl transformarea invers, ntr-un limbaj de nivel nalt precum C#. Un astfel de decompilator este .NET Reflector, pe care MSDN Magazine l-a numit unul din utilitarele obligatorii pentru un dezvoltator .NET. Programul este folosit deseori de ctre programatori pentru a nelege structura intern a bibliotecilor .NET pentru care codul surs nu este disponibil. S considerm urmtorul program simplu:
public class Program { static void Main(string[] args) { string[] s = new string[] { "Hello, ", "World!" }; for (int i = 0; i < s.Length; i++) Console.Write(s[i]); Console.WriteLine(Environment.NewLine + "ok"); // NewLine pentru Windows este "\r\n" } }

Dup compilare, assembly-ul rezultat (n acest caz fiierul exe) se deschide n .NET Reflector. Programul permite navigarea prin namespace-uri, clase i metode. Cu click-dreapta se deschide un meniu din care se poate selecta opiunea de decompilare (engl. disassemble), ca n

19
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

figura 1.3. Din combo-box-ul din bara de instrumente se alege limbajul n care s se realizeze decompilarea.

Figura 1.3. Programul .NET Reflector

Iat rezultatele decompilrilor n mai multe limbaje: C#

20
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 1. Compilarea, decompilarea i obscurizarea programelor C#

Visual Basic

Managed C++

Delphi

21
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

CIL

22
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 1. Compilarea, decompilarea i obscurizarea programelor C#

3.3. Compilarea n modurile Debug i Release


Dei majoritatea optimizrilor se realizeaz n momentul compilrii JIT, chiar i compilatorul C# poate efectua analize ale codului i unele simplificri n vederea creterii vitezei de execuie. Compilarea n mod Debug este destinat facilitrii procesului de descoperire a erorilor i de aceea codul generat urmeaz mai fidel structura codului surs. n modul Debug, compilatorul JIT genereaz un cod mai uor de depanat, ns mai lent. n schimb, compilarea n mod Release poate introduce optimizri suplimentare. Aceste opiuni pot fi controlate din mediul Visual Studio, astfel: View Solution Explorer Project Properties Build. n modul Release, opiunea Optimize code este activat. De asemenea, n View Solution Explorer Project Properties Build Advanced Output, se precizeaz crearea sau nu a unui fiier pdb (program database) care conine informaii ce fac legtura ntre codul CIL generat i codul surs iniial, utile n special n faza de Debug. n continuare, vor fi prezentate unele diferene de compilare n mod Debug (prima imagine, de sus), respectiv Release (a doua imagine, de jos).

23
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

a) Declararea variabilelor n locul n care sunt utilizate.

Interesant este faptul c aceste optimizri nu apar ntotdeauna. De exemplu, o metod simpl cum ar fi urmtoarea nu va fi optimizat, dei principiul este acelai ca mai sus.
public void Locals() { int i; for (i = 0; i < 3; i++) DoSomething(); for (i = 2; i < 5; i++) DoSomething(); }

24
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 1. Compilarea, decompilarea i obscurizarea programelor C#

b) Transformarea buclelor while n bucle for

25
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

c) Eliminarea iniializrilor cu null

d) Eliminarea variabilelor neutilizate

26
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 1. Compilarea, decompilarea i obscurizarea programelor C#

e) Optimizarea iniializrilor n constructor

27
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

f) Optimizarea blocurilor switch

Prin urmare, programatorul nu trebuie s fac optimizri, mai ales cnd acestea scad claritatea codului. Singurele optimizri recomandate sunt acelea care scad complexitatea unui algoritm cu cel puin o clas, de
28
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 1. Compilarea, decompilarea i obscurizarea programelor C#

exemplu de la O(n2) la O(log n) sau O(n). n rest, compilatorul face oricum transformri ale codului, adaptate mediului de execuie existent. Eventualele optimizri manuale pot conduce n cel mai ru caz la secvene nestandard care nu sunt recunoscute de compilator i care pot scdea de fapt performanele aplicaiei. Codul pregtit pentru livrarea comercial trebuie ntotdeauna compilat n modul Release.

3.4. Obscurizarea codului. Dotfuscator


Codul obscurizat (engl. obfuscated) este un cod foarte greu de citit i de neles. Deoarece prin decompilare orice program .NET devine de fapt open-source, obscurizarea este una din modalitile prin care se poate pstra secretul asupra codului aplicaiilor realizate. Visual Studio include un astfel de instrument, numit Dotfuscator Community Edition care are o serie de limitri fa de versiunea Professional. Printre cele mai importante sunt criptarea irurilor de caractere, comprimarea assembly-urilor obscurizate i diferite scheme de redenumire. Nu este un instrument infailibil, ns este util pentru aplicaiile de importan medie. Dotfuscator Community Edition poate fi pornit din mediul Visual Studio din meniul: Tools Dotfuscator Community Edition. Mai nti se ncarc assembly-ul dorit, iar din tab-ul Rename se pot selecta namespace-urile, tipurile i metodele care se doresc redenumite, implicit toate. Apoi se ruleaz proiectul apsnd butonul Build (figura 1.4).

Figura 1.4. Instrumentul Dotfuscator

Rezultatul va fi un nou assembly, cu numele interne schimbate.


29
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

S considerm urmtorul exemplu. n stnga este programul iniial iar n dreapta codul dezasamblat dup obscurizare.
public class AddingNumbers { public int AddTwo(int a, int b) { return a + b; } public int AddThree(int a, int b, int c) { return a + b + c; } } class Program { static void Main(string[] args) { int x = 1, y = 2, z = 3; AddingNumbers an = new AddingNumbers(); int r1 = an.AddTwo(x, y); Console.WriteLine(r1); int r2 = an.AddThree(x, y, z); Console.WriteLine(r2); } } } class b { private static void a(string[] A_0) { int num = 1; int num2 = 2; int num3 = 3; a a = new a(); Console.WriteLine(a.a(num, num2)); Console.WriteLine( a.a(num, num2, num3)); } } public class a { public int a(int A_0, int A_1) { return (A_0 + A_1); } public int a(int A_0, int A_1, int A_2) { return ((A_0 + A_1) + A_2); }

4. Aplicaii
4.1. Realizai un program de tip consol n care s creai cte o metod pentru fiecare din situaiile de mai jos. Compilai programul n mod Debug cu Debug Info full, respectiv Release cu Debug Info none. Variabile locale nefolosite:
int a = 4; int b = 3; double c = 4; bool ok = false; Console.WriteLine(ok); 30
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 1. Compilarea, decompilarea i obscurizarea programelor C#

Ramuri ale expresiilor condiionale:


int b = 3; double c = 4; bool ok = false; if (b < 3) if (c > 3) ok = true; Console.WriteLine(ok);

Cod imposibil de atins:


if (true) Console.WriteLine("ok"); if (false) Console.WriteLine("false"); else Console.WriteLine("true"); return; Console.WriteLine("finished");

Expresii aritmetice:
int a = 2 + 4 + 5; double b = 9 / 5.0 + a + 9 + 5; b++;

Instruciuni goto (nerecomandate, deoarece afecteaz calitatea structurii codului):

int b = 10; if (b < 20) { Console.WriteLine("true"); } else { goto After; } After: Console.WriteLine("goto");

31
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C# bool a = (b < 4); if (a) { goto C; } Console.WriteLine(1); C: Console.WriteLine(2);

Apelarea metodelor din obiecte (pentru aceasta creai o clas Test cu o metod MyMethod):
Test t = new Test(); int a = t.MyMethod(); Console.WriteLine(a);

De observat decompilarea urmtoarei secvene n mod Release: ce elemente i pstreaz numele chiar n absena fiierului pdb? Care sunt numele implicite date de .NET Reflector pentru diferite tipuri de date?
int integer = 3; double real = 3.14; bool boolean = true; Console.WriteLine("Integer: " + integer); Console.WriteLine("Real: " + real); Console.WriteLine("Boolean: " + boolean); NumberForTestingOnly t = new NumberForTestingOnly(); Console.WriteLine("Test object: " + t.ReturnDouble(4)); public class NumberForTestingOnly { public int ReturnDouble(int par) { return par * 2; } }

32
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 1. Compilarea, decompilarea i obscurizarea programelor C#

Not: dei de multe ori termenii argument i parametru se folosesc ca sinonime, exist o diferen ntre aceste noiuni. n exemplul anterior: ReturnDouble(int par) par este parametru; t.ReturnDouble(4) 4 este argument.

4.2. Creai un program cu 3 clase, fiecare clas cu 4 metode i obscurizai-l utiliznd instrumentul Dotfuscator. Pentru a vedea rezultate interesante, cteva metode din aceeai clas trebuie s aib aceeai semntur cu excepia numelui, iar celelalte s aib semnturi diferite. Instaniai obiecte de aceste tipuri i apelai metodele corespunztoare.

33
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

34
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 2

Stilul de scriere a codului. Tratarea excepiilor. Interfaa grafic cu utilizatorul


1. Obiective 2. Stilul de scriere a codului 3. Tratarea excepiilor 4. Interfaa cu utilizatorul 5. Interfaa grafic cu utilizatorul n Microsoft Visual Studio .NET 6. Elemente de C# 7. Aplicaii

1. Obiective
Obiectivele capitolului 2 sunt urmtoarele: Sublinierea importanei unui stil unitar de scriere a codului ntr-o firm care dezvolt produse software; Descrierea standardului de scriere a codului pe care l vom utiliza n ghidul de aplicaii de ingineria programrii; Explicarea modalitilor de tratare a excepiilor n C#; Prezentarea unor aspecte legate de dezvoltarea de aplicaii cu interfa grafic; Prezentarea modului de lucru cu proprieti C#.

2. Stilul de scriere a codului


Unul din scopurile urmrite la scrierea programelor trebuie s fie ntreinerea ulterioar a codului, adic facilitarea modificrilor i completrilor viitoare, foarte probabil de ctre persoane diferite dect autorul iniial. De asemenea, unele studii au artat c dup 6 luni de la scrierea unui program, acesta i apare la fel de strin autorului ca i un program scris de altcineva. Unul din aspectele principale ale codului uor de ntreinut este posibilitatea de a gsi anumite buci de cod i de a le modifica fr a afecta celelalte seciuni. Claritatea este esenial. Altfel, n cazul programelor de
35
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

mari dimensiuni, aa cum sunt majoritatea situaiilor n cazul produselor software comerciale, n locul lucrului efectiv pentru adugarea de funcionaliti se va pierde timpul ncercndu-se s se gseasc poriunile relevante de cod care trebuie modificate. Formatarea codului poate simplifica nelegerea structurii semantice sau poate cauza confuzie. Poate chiar ascunde defecte greu de depistat, de exemplu:
bool error = DoSomething(); if (error) Console.WriteLine("Eroare"); Environment.Exit(1);

/// !!!

Nu conteaz ct de bine este proiectat un program; dac prezentarea sa arat neglijent, va fi neplcut de lucrat cu el.

2.1. Acoladele
Exist dou modaliti principale de plasare a acoladelor. Stilul Kernighan i Ritchie este bazat pe dorina de a afia ct mai multe informaii ntr-un mod compact:
int KernighanRitchie() { int a = 0, b = 0; while (a != 10) { a++; b--; } return b; }

Acest stil poate fi folosit la prezentri de cod sau n situaii n care spaiul disponibil pentru afiarea codului este redus, de exemplu ntr-un material tiprit. Stilul extins sau stilul Allman este recomandat de Microsoft pentru limbajul C#:

36
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 2. Stilul de scriere a codului. Tratarea excepiilor. Interfaa grafic cu utilizatorul int Extended() { int a = 0, b = 0; while (a != 10) { a++; b--; } return b; }

Avantajul principal al acestuia este claritatea, deoarece blocurile de cod sunt evideniate prin alinierea acoladelor. Este stilul pe care l vom utiliza n acest ghid de aplicaii.

2.2. Standarde de programare


Muli programatori fr experien industrial, dei foarte buni, refuz la nceput aplicarea unor standarde impuse. Dac programul este corect, ei nu neleg de ce trebuie aliniat altfel sau de ce trebuie schimbate numele variabilelor sau metodelor. Este important de avut n vedere faptul c nu exist un stil perfect, deci rzboaiele privind cea mai bun formatare nu pot fi ctigate. Toate stilurile au argumente pro i contra. Majoritatea firmelor serioase de software au standarde interne de scriere a programelor, care definesc regulile pentru prezentarea codului. Aceste standarde cresc calitatea programelor i sunt importante deoarece toate proiectele livrate n afara organizaiei vor avea un aspect ngrijit i coerent, de parc ar fi fost scrise de aceeai persoan. Existena mai multor stiluri distincte ntr-un proiect indic lipsa de profesionalism. Faptul c un programator crede c stilul su propriu este cel mai frumos i cel mai uor de neles nu are nicio importan. Un stil care unui programator i pare n mod evident cel mai bun poate reprezenta o problem pentru altul. De exemplu:
using System . Windows . Forms; namespace LabIP { public class HelloWorld:System . Windows . Forms . Form { public HelloWorld ( ) { InitializeComponent ( ); } 37
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C# protected override void Dispose ( bool disposing ) { if( disposing ) { if( components != null ) { components . Dispose ( ); } } base . Dispose ( disposing ); } static void Main ( ) { Application . Run ( new HelloWorld ( ) ); } private void button1_Click ( object sender , System . EventArgs e ) { string STRING = "Hello World!"; display ( STRING ); } private void display ( string STR ) { MessageBox . Show ( STR , ":-)" ); } } }

Acest program nu a fost aliniat aleatoriu, ci folosind opiunile din mediul Visual Studio: Tools Options Text Editor C# Formatting. n acelai mod, stilul personal al unui programator poate prea la fel de ciudat altuia. Beneficiile adoptrii unui stil unitar de ctre toi membrii unei organizaii depesc dificultile iniiale ale adaptrii la un stil nou. Chiar dac nu este de acord cu standardul impus, un programator profesionist trebuie s se conformeze. Dup ce va folosi un timp stilul firmei, se va obinui cu el i i se va prea perfect natural. n prezentul ghid de aplicaii vom utiliza un standard bazat pe recomandrile Microsoft pentru scrierea programelor C#. Este bine ca regiunile de program s fie delimitate cu ajutorul cuvntului cheie region, de exemplu:
#region Fields private DateOfBirth _dob; private Address _address; #endregion

Dac toate seciunile unei clase sunt delimitate pe regiuni, pagina ar trebui s arate n felul urmtor atunci cnd toate definiiile sunt colapsate:

38
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 2. Stilul de scriere a codului. Tratarea excepiilor. Interfaa grafic cu utilizatorul

2.3. Convenii pentru nume


Cheia alegerii unor nume potrivite este nelegerea rolului construciilor respective. De exemplu, dac nu putem gsi un nume bun pentru o clas sau pentru o metod, ar fi util s ne ntrebm dac tim ntr-adevr la ce folosete aceasta sau dac chiar este necesar s existe n program. Dificultile la alegerea unui nume potrivit pot indica probleme de proiectare. Un nume trebuie s fie: Descriptiv: Oamenii i pstreaz deseori percepiile iniiale asupra unui concept. Este important deci crearea unei impresii iniiale corecte despre datele sau funcionalitile unui program prin alegerea unor termeni care s descrie exact semnificaia i rolul acestora. Numele trebuie alese din perspectiva unui cititor fr cunotine anterioare, nu din perspectiva programatorului; Adecvat: Pentru a da nume clare, trebuie s folosim cuvinte din limbajul natural. Programatorii au tendina s utilizeze abrevieri i prescurtri, ns acest lucru conduce la denumiri confuze. Nu are
39
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

importan faptul c un identificator este lung ct vreme este lipsit de ambiguitate. Denumirea st nu este o alegere potrivit pentru conceptul numarStudenti. Regula de urmat este: trebuie preferat claritatea fa de laconism. Excepiile sunt contoarele de bucle, de exemplu clasicul for (int i = 0; i < length; i++). Acestea de multe ori nu au o semnificaie de sine stttoare, sunt construcii specifice (idiomuri) ale limbajelor evoluate din C i de obicei se noteaz cu o singur liter: i, j, k etc.; Coerent: Regulile de numire trebuie respectate n tot proiectul i trebuie s se conformeze standardelor firmei. O clas precum cea de mai jos nu prezint nicio garanie de calitate:
class badly_named : MyBaseClass { public void doTheFirstThing(); public void DoThe2ndThing(); public void do_the_third_thing(); }

Pentru descrierea tipurilor de nume, exist n englez o serie de termeni care nu au un echivalent exact n limba romn: Pascal case: Primul caracter al tuturor cuvintelor este o majuscul iar celelalte caractere sunt minuscule, de exemplu: NumarStudenti; Camel case: Pascal case cu excepia primului cuvnt, care ncepe cu liter mic, de exemplu: numarStudenti.

Pentru denumirea conceptelor dintr-un program C#, vom adopta conveniile din tabelul 2.1.
Tabelul 2.1. Convenii pentru denumirea conceptelor dintr-un program C#

Concept

Namespace-uri Clase Interfee Metode Variabile locale Variabile booleene

Convenie

Pascal case Pascal case Pascal case precedat de I Pascal case Camel case Prefixate cu is

Exemple
namespace LaboratorIP class HelloWorld interface IEntity void SayHello() int totalCount = 0; bool isModified;

40
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 2. Stilul de scriere a codului. Tratarea excepiilor. Interfaa grafic cu utilizatorul

Concept

Parametrii metodelor Cmpuri private 1 Proprieti 2 Constante, cmpuri readonly publice 3 Controale pentru interfaa grafic 4 Excepii
1

Convenie
Camel case Camel case precedat de underscore Pascal case Pascal case Camel case precedat de tipul controlului Pascal case cu terminaia Exception

Exemple
void SayHello(string name) string _address; Address const int MaxSpeed = 100; buttonOK checkBoxTrigonometric comboBoxFunction MyException PolynomialException

Pn la versiunea Visual Studio 6.0, programatorii utilizau n C++ notaia maghiar a lui Simonyi pentru variabile, care indica i tipul acestora, de exemplu nAge pentru int. Pentru variabilele membru se folosea prefixul m_, de exemplu m_nAge. Pentru limbajul C#, Microsoft nu mai recomand utilizarea acestor notaii. Pentru cmpurile private exist cteva avantaje la prefixarea cu underscore: cmpurile clasei vor avea o notaie diferit de variabilele locale; cmpurile clasei vor avea o notaie diferit de parametrii metodelor, astfel nct se vor evita situaiile de iniializare de genul this.x = x, unde this.x este cmpul iar x este parametrul metodei; n IntelliSense, la apsarea tastei _ vor aprea grupate toate cmpurile.

Avantajul utilizrii acestei convenii se manifest mai ales n situaii precum aceea de mai jos:
private int description; // ortografie corect public Constructor(int descripton) // ortografie incorect pentru "description" { this.description = description; // ortografie corect n ambele pri, cmpul rmne 0 }
2 3 4

Proprietile vor fi detaliate n seciunea 6.2. n mare, tot ce e public ntr-o clas trebuie s nceap cu liter mare

Aceast notaie are avantajul c, dei numele sunt mai lungi, sunt lipsite de ambiguitate. Exist i stilul prefixrii cu o abreviere de 3 litere, de exemplu btn pentru Button, ckb pentru CheckBox etc. Pentru controale mai puin uzuale, semnificaiile prefixelor nu mai sunt evidente: pbx, rdo, rbl etc.

41
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

3. Tratarea excepiilor
Tratarea erorilor se fcea n C prin returnarea unei valori, de obicei int, care semnifica un cod de eroare. De exemplu, dac o funcie trebuia s deschid un fiier, ea putea ntoarce 0 dac totul a funcionat normal, respectiv codul de eroare 1 dac fiierul nu exista. n funcia apelant, programatorul trebuia s trateze codul returnat:
int err = OpenFile(s);

Cu toate acestea, programatorul era liber s apeleze funcia direct, OpenFile(s), fr a mai testa valoarea returnat. Programul putea fi testat cu succes, deoarece fiierul exista, ns putea s nu mai funcioneze dup livrare. Majoritatea funciilor Windows API returneaz un cod dintr-o list cu sute de valori posibile, ns puini programatori testeaz aceste valori individual. Tratarea excepiilor a aprut pentru a da posibilitatea programelor s surprind i s trateze erorile ntr-o manier elegant i centralizat, permind separarea codului de tratare a erorilor de codul principal al programului, ceea ce face codul mai lizibil. Astfel, este posibil tratarea: tuturor tipurilor de excepii; tuturor excepiilor de un anume tip; tuturor excepiilor de tipuri nrudite.

Odat ce o excepie este generat, ea nu poate fi ignorat de sistem. Funcia care detecteaz eroarea poate s nu fie capabil s o trateze i atunci se spune c arunc (throw) o excepie. Totui, nu putem fi siguri c exist un caz de tratare pentru orice excepie. Dac exist o rutin potrivit, excepia este tratat, dac nu, programul se termin. Rutinele de tratare a excepiilor pot fi scrise n diverse feluri, de exemplu examineaz excepia i apoi nchid programul sau re-arunc excepia. Structura blocurilor try-catch pentru tratarea excepiilor este urmtoarea:

42
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 2. Stilul de scriere a codului. Tratarea excepiilor. Interfaa grafic cu utilizatorul FuncieApelat { ... if (condiii) throw ... ... } FuncieApelant { ... try { FuncieApelat(); } catch (Exception e) // catch fr parametru dac nu intereseaz detaliile excepiei { // cod pentru tratarea excepiei, care prelucreaz parametrul e } ... }

Codul care ar putea genera o excepie se introduce n blocul try. Excepia este aruncat (throw) din funcia care a fost apelat, direct sau indirect. Excepiile care apar n blocul try sunt captate n mod normal de blocul catch care urmeaz imediat dup acesta. Un bloc try poate fi urmat de unul sau mai multe blocuri catch. Dac se execut codul dintr-un bloc try i nu se arunc nicio excepie, toate rutinele de tratare sunt ignorate, iar execuia programului continu cu prima instruciune de dup blocul (sau blocurile) catch. n C#, tipul trimis ca parametru este de obicei Exception:
try { FunctieApelata(); } catch (Exception ex) { ... }

43
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

De cele mai multe ori, ne intereseaz proprietatea Message (de tip string) a unui astfel de obiect, care arat cauza erorii. Textul respectiv este precizat n funcia care arunc excepia.
private void FunctieApelata(int a) { if (a == 0) throw new Exception("Argument zero"); } private void FunctieApelanta() { FunctieApelata(0); }

Dac excepia nu este tratat, va aprea un mesaj de atenionare cu textul dorit (figura 2.1).

Figura 2.1. Mesaj de excepie

Mesajul de eroare trebuie preluat n program n blocul catch:


private void FunctieApelanta() { try { FunctieApelata(0); } catch (Exception ex) { // ex.Message este "Argument zero" } }

44
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 2. Stilul de scriere a codului. Tratarea excepiilor. Interfaa grafic cu utilizatorul

Programatorul i poate defini propriile tipuri de excepii, n cazul n care are nevoie s trimit informaii suplimentare privind excepia. Acestea trebuie ns derivate din clasa Exception:
public class MyException: Exception { public int _info; // informaie suplimentar // n constructor se apeleaz i constructorul clasei de baz public MyException(int val) : base() { _info = val; } }

Utilizarea acestui tip se face astfel:


throw new MyException(3);

Dup un try pot exista mai multe blocuri catch. Ele trebuie dispuse n ordinea invers a derivrii tipurilor, de la particular la general:
try { FunctieApelata(x); } catch (MyException myex) { ... } catch (Exception ex) { ... }

Alt ordine nu este permis, eroarea fiind descoperit la compilare: A previous catch clause already catches all exceptions of this or a super type ('System.Exception').

45
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

3.1. Tratarea excepiilor pe firul de execuie al aplicaiei


Uneori pentru a fi siguri c nu am lsat vreo excepie netratat, putem trata global toate excepiile aprute pe firele de execuie ale aplicaiei, n maniera descris n continuare:
static class Program { static void Main() { // Adugarea unui event handler pentru prinderea excepiilor // din firul principal al interfeei cu utilizatorul Application.ThreadException += new ThreadExceptionEventHandler(OnThreadException); // Adugarea unui event handler pentru toate firele de execuie din appdomain // cu excepia firului principal al interfeei cu utilizatorul AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException); Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new MyForm()); // MyForm este fereastra principal a programului } // Trateaz excepiile din firul principal al interfeei cu utilizatorul static void OnThreadException(object sender, ThreadExceptionEventArgs t) { // Afieaz detaliile excepiei MessageBox.Show(t.Exception.ToString(), "OnThreadException"); } // Trateaz excepiile din toate celelalte fire de execuie static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) { // Afieaz detaliile excepiei MessageBox.Show(e.ExceptionObject.ToString(), "CurrentDomain_UnhandledException"); } }

46
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 2. Stilul de scriere a codului. Tratarea excepiilor. Interfaa grafic cu utilizatorul

4. Interfaa cu utilizatorul
Interfaa cu utilizatorul permite acestuia s interacioneze cu aplicaia. Exist dou tipuri principale de interfee: interfa cu utilizatorul de tip caracter (engl. character user interface, CUI); interfa cu utilizatorul de tip grafic (engl. graphical user interface, GUI).

Un exemplu de interfa de tip caracter este interfaa la linia de comand a sistemului de operare MS-DOS. Cnd se folosete o astfel de interfa, n general utilizatorul trebuie s memoreze i s tasteze comenzi text. De aceea, interfeele de acest tip pot fi mai dificil de utilizat i necesit o oarecare pregtire a utilizatorului. O interfa grafic ncearc s simplifice comunicarea. Graficele reprezint obiecte pe care utilizatorul le poate manipula i asupra crora poate efectua aciuni. Deoarece utilizatorul nu trebuie s tie un limbaj de comand, o interfa grafic bine proiectat este mai uor de folosit dect o interfa de tip caracter.

4.1. Proiectarea comenzilor i interaciunilor


Dac ierarhia de comenzi trebuie s se integreze ntr-un sistem de interaciuni deja existent, trebuie mai nti studiat acesta. Se stabilete o ierarhie iniial de comenzi care poate fi prezentat utilizatorilor n mai multe moduri: o serie de opiuni dintr-un meniu, o bar de instrumente (toolbar) sau o serie de imagini (icons). Apoi, aceast ierarhie se rafineaz prin ordonarea serviciilor din fiecare ramur a ierarhiei n ordinea logic n care trebuie s se execute, cele mai frecvente servicii aparrnd primele n list. Limea i adncimea ierarhiei trebuie proiectate n aa fel nct s se evite suprancarea memoriei de scurt durat a utilizatorului. De asemenea, trebuie minimizat numrul de pai sau de aciuni (apsri ale mouse-ului, combinaii de taste) pe care trebuie s le efectueze acesta pentru a-i ndeplini scopul. Interaciunile cu factorul uman pot fi proiectate pe baza urmtoarelor criterii:

47
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

coerena: se recomand utilizarea unor termeni i aciuni cu semnificaii unice, bine precizate i care se regsesc n mod unitar n tot sistemul; numrul mic de pai: trebuie s se minimizeze numrul de aciuni pe care trebuie s le ndeplineasc utilizatorul; evitarea aerului mort (engl. dead air): utilizatorul nu trebuie lsat singur, fr niciun semnal, atunci cnd ateapt ca sistemul s execute o aciune. El trebuie s tie c sistemul execut o aciune i ct din aciunea respectiv s-a realizat; operaiile de anulare (engl. undo): se recomand furnizarea acestui serviciu datorit erorilor inerente ale utilizatorilor; timpul scurt i efortul redus de nvare: de multe ori, utilizatorii nu citesc documentaia, de aceea se recomand furnizarea n timpul execuiei a unor soluii pentru problemele aprute; aspectul estetic al interfeei: oamenii utilizeaz mai uor un produs software cu un aspect plcut.

Se recomand folosirea de icoane i controale similare celor din produsele software cu care utilizatorul este familiarizat. Dac are de-a face cu acelai aspect exterior, acesta i va folosi cunotinele anterioare pentru navigarea prin opiunile programului, ceea ce va reduce i mai mult timpul de instruire.

4.2. Considerente practice


Elementele interfeei grafice trebuie s fie coerente, adic s aib stiluri, culori i semnificaii similare n toat aplicaia. Un tabel centralizat de cuvinte cheie poate ajuta la alegerea textelor sau etichetelor de ctre proiectanii interfeei care lucreaz la acelai sistem. Aceast tabel conine lista de cuvinte folosite n toat interfaa i care nseamn aceeai lucru peste tot. O interfa clar este uor de neles. Metaforele utilizate trebuie s fie n acord cu experiena utilizatorilor n legtur cu obiectele din lumea real pe care le reprezint. De exemplu, icoana unui co de gunoi poate reprezenta o funcie de gestionare a fiierelor nedorite (gen Recycle Bin): fiierele pot fi introduse n co, unde rmn i pot fi regsite pn cnd coul este golit. Erorile trebuie identificate imediat folosind un mesaj inofensiv. Utilizatorul trebuie s-i poat repara o greeal ori de cte ori este posibil acest lucru iar documentaia programului sau manualul de utilizare trebuie
48
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 2. Stilul de scriere a codului. Tratarea excepiilor. Interfaa grafic cu utilizatorul

s l ajute n acest sens. Mesajele critice trebuie folosite numai atunci cnd utilizatorul trebuie avertizat c unele date pot fi pierdute sau deteriorate dac nu acioneaz imediat. Chiar dac nu sunt probleme, furnizarea informaiilor despre starea sistemului face interfaa mai prietenoas. Totui, aceste mesaje pot deveni suprtoare dac sunt folosite prea des. Pot fi afiate i mesaje despre cursul unei aciuni sau despre timpul dup care se va termina o activitate. Dac o aciune dureaz aproximativ 6-8 secunde, se poate folosi un indicator de tip clepsidr. Pentru activiti mai lungi de 8 secunde, se pot folosi indicatoare de tip procentaj sau timp rmas. Utilizatorii trebuie s aib de asemenea posibilitatea ntreruperii sau anulrii acestor aciuni de durat. Mesajele sonore trebuie n general evitate deoarece pot fi suprtoare, distrag atenia iar semnificaia sunetelor poate depinde de contextul cultural al utilizatorilor. Culoarea joac un rol important n proiectarea unei interfee grafice. Folosirea corect a culorilor face interfaa clar i uor de navigat. Totui, dac nu sunt folosite cu atenie, culorile pot distrage atenia utilizatorului. Culorile pot fi utilizate pentru a identifica prile importante ale interfeei. Prea multe culori strlucitoare fac textul dificil de citit. Trebuie de asemenea evitat un fundal complet alb i nu trebuie folosite mai mult de 4 culori ntr-o fereastr. Interpretarea culorilor este foarte subiectiv. Poate depinde de asociaii culturale, psihologice i individuale. Deci, n general, cel mai bine este s folosim culori subtile i neexagerate. Utilizatorii presupun de multe ori c exist o legtur ntre obiectele de aceeai culoare, aa c trebuie s fim ateni s nu folosim aceeai culoare pentru obiecte fr legtur. Culorile nu trebuie s fie singura surs de informaii deoarece unii utilizatori nu pot distinge anumite culori, iar alii pot avea monitoare care nu suport o gam larg de culori. Ca i culorile, icoanele pot pune n valoare o interfa grafic, dac sunt folosite corect. Icoanele bine proiectate ofer utilizatorului un mod accesibil de comunicare cu aplicaia. Exist cteva elemente de care trebuie s inem seama la proiectarea acestora: un stil i o dimensiune comun pentru toate icoanele dau interfeei un aspect coerent; desenele ajut utilizatorul s recunoasc metaforele i s-i aminteasc funciile;
49
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

conturarea icoanelor cu negru le face s ias n eviden din fundal; icoanele pot fi afiate n trei mrimi: 48 x 48, 32 x 32 i 16 x 16 pixeli; acestea trebuie s fie uor de recunoscut chiar i atunci cnd sunt afiate la dimensiunea de 16 x 16 pixeli; dei o icoan poate fi accentuat prin culoare, ea trebuie s poat fi recunoscut i n varianta alb-negru.

Icoanele bine proiectate i comunic funciile cu claritate i cresc utilizabilitatea interfeei, ns o icoan neclar poate deruta utilizatorii i poate crete numrul de erori. Putem folosi etichete text pentru a ne asigura c semnificaia unei icoane este clar. Cteodat este cel mai bine s folosim imagini tradiionale deoarece utilizatorul este familiarizat cu ele. O icoan bine proiectat trebuie s poat fi distins cu uurin de celelalte icoane din jurul su, iar imaginea trebuie s fie simpl i potrivit contextului interfeei. Corpurile de liter (font-urile) utilizate ntr-o interfa grafic nu trebuie amestecate. Ca i n cazul culorilor, prea multe font-uri pot distrage atenia utilizatorului.

4.3. Profilurile utilizatorilor


Pentru a crea o interfa grafic utilizabil, trebuie s cunoatem profilul utilizatorului, care descrie ateptrile i nevoile acestuia. Un mod potrivit de a determina profilul utilizatorului este prin observare la locul su de munc. Poate fi folositoare sugestia ca utilizatorul s gndeasc cu voce tare atunci cnd lucreaz cu prototipul unei interfee. Aproape ntotdeauna va exista un procent de utilizatori nceptori iar interfaa trebuie s aib grij de acetia. De exemplu, putem asigura alternative la acceleratori (combinaii de taste pentru anumite funcii) i putem preciza shortcut-urile n opiunile meniurilor. Profilurile utilizatorilor se ncadreaz n general n trei categorii: Utilizatorul comod dorete s foloseasc interfaa imediat, cu foarte puin antrenament. Acest tip de utilizator prefer utilizarea mouse-ului, atingerea sensibil a ecranului sau stiloul electronic. Navigarea simpl este important deoarece utilizatorul comod nu ine minte ci complicate. Afiarea unei singure ferestre la un moment dat simplific navigarea. Pentru a face o interfa grafic accesibil unui utilizator de acest tip, ea trebuie s se bazeze pe
50
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 2. Stilul de scriere a codului. Tratarea excepiilor. Interfaa grafic cu utilizatorul

recunoaterea unei icoane, mai degrab dect pe amintirea a ceea ce reprezint icoana. Acest lucru se poate realiza prin folosirea unei multitudini de grafice i de opiuni n meniuri; Utilizatorul rapid dorete un timp de rspuns ct mai mic, aa nct trebuie evitate prea multe redesenri ale ferestrelor. Acest tip de utilizator prefer n general s foloseasc tastatura i mai puin mouse-ul. Utilizatorii de acest tip au n general timp pentru instruire i sunt dispui s renune la faciliti n favoarea vitezei. Acceleratorii le permit s lucreze mai repede; Utilizatorul energic este de nivel avansat i are experien cu interfeele grafice. Acesta nu i dorete o instruire de durat i se ateapt s foloseasc interfaa imediat. Deoarece este sigur pe sine i i place s exploreze, trebuie ntotdeauna asigurat o opiune de anulare (engl. undo). Alte trsturi pe care le ateapt sunt schimbri limitate ale modului de afiare, multitasking i posibilitatea particularizrii i individualizrii aspectului interfeei grafice.

5. Realizarea programelor cu interfaa grafic cu utilizatorul n Microsoft Visual Studio .NET


Cnd este creat un nou proiect C# de tip Windows Application, n mijlocul ecranului (figura 2.2), apare un formular (Form) fereastra principal a programului, n care se vor aduga diverse componente de control: butoane, text-box-uri etc. n partea din stnga a ecranului exist o bar de instrumente (View Toolbox sau Ctrl+Alt+X) din care se aleg cu mouse-ul componentele ce trebuie adugate n fereastr. Pentru adugarea unei componente, programatorul va face click cu mouse-ul pe imaginea corespunztoare din toolbox, apoi va face click n formular, n locul unde dorete s apar componenta respectiv. Odat introduse n fereastr, componentele pot fi mutate, redimensionate, copiate sau terse. n dreapta este o fereastr de proprieti (View Properties Window sau F4). De aici, fiecrei componente folosite i se pot modifica proprietile, adic aspectul exterior, aa cum va aprea n program, sau caracteristicile funcionale interne. De asemenea, se pot selecta evenimentele corespunztoare componentei care vor fi tratate n program.

51
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

Figura 2.2. Mediul de dezvoltare Microsoft Visual Studio

n continuare, vor fi prezentate cteva componente de control folosite practic n orice program Windows. Pentru fiecare component, vor fi amintite unele proprieti i metode uzuale. Pentru o descriere mai amnunit, se recomand consultarea documentaiei MSDN. Application Clasa Application ncapsuleaz o aplicaie Windows. Clasa conine metode i proprieti statice pentru managementul unei aplicaii, cum ar fi metode pentru pornirea i oprirea programului, prelucrarea mesajelor Windows i proprieti corespunztoare informaiilor despre aplicaie. Se poate observa c n scheletul de program creat implicit de mediul de dezvoltare, n metoda Main() este pornit programul pe baza clasei corespunztoare ferestrei principale:
Application.Run(new MainForm());

52
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 2. Stilul de scriere a codului. Tratarea excepiilor. Interfaa grafic cu utilizatorul

Form Clasa System.Windows.Forms.Form corespunde unei ferestre standard. O aplicaie poate avea mai multe ferestre una principal, cteva secundare i cteva ferestre de dialog. Unele proprieti: Icon icoana care apare n bara de titlu a ferestrei; FormBorderStyle nfiarea i comportamentul chenarului, de exemplu, dac fereastra poate fi redimensionat; Text titlul ferestrei, care apare n bara de titlu i n taskbar; StartPosition locul unde apare fereastra pe ecran; Size dimensiunea (nlimea i limea ferestrei); de obicei se stabilete prin redimensionarea ferestrei cu mouse-ul, n procesul de proiectare. Cteva evenimente: Load, Closed pentru diverse iniializri n momentul crerii ferestrei sau prelucrri n momentul nchiderii acesteia;

n general, pentru tratarea unui eveniment n C#, este selectat mai nti obiectul de tipul dorit (la noi fereastra), apoi n fereastra de proprieti se alege tab-ul de evenimente i se identific evenimentul cutat.

Figura 2.3. Editarea proprietilor componentelor

53
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

Dup un dublu-click, ca n figura 2.3, se va crea automat o nou metod vid corespunztoare evenimentului, iar utilizatorul va trebui numai s scrie n corpul funciei comenzile dorite.

Button Clasa System.Windows.Forms.Button corespunde unui buton. Cteva proprieti i evenimente: Text textul nscris pe buton; Click funcia executat cnd butonul este apsat. Label Clasa System.Windows.Forms.Label nscrie un text undeva n fereastr. Una din proprieti: Text textul nscris. TextBox Clasa System.Windows.Forms.TextBox corespunde unei csue de editare de text. Cteva proprieti i evenimente: Text textul din csu (de tip string); Multiline textul poate fi introdus pe o singur linie (false) sau pe mai multe (true); ScrollBars indic prezena unor bare de derulare (orizontale, verticale) dac proprietatea Multiline este true; Enabled componenta este activat sau nu (true / false); ReadOnly textul poate fi modificat sau nu de utilizator (true / false); CharacterCasing textul poate aprea normal (Normal), numai cu litere mici (Lower) sau numai cu litere mari (Upper); TextChanged evenimentul de tratare a textului n timp real, pe msur ce acesta este introdus.
54
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 2. Stilul de scriere a codului. Tratarea excepiilor. Interfaa grafic cu utilizatorul

ComboBox Clasa System.Windows.Forms.ComboBox corespunde unui combobox, care combin un text-box cu o list. Cteva proprieti i evenimente: Text textul din partea de editare; Items lista de obiecte din partea de selecie, care se poate introduce i prin intermediul ferestrei de proprieti; SelectedIndex numrul articolului din list care este selectat (0 primul, 1 al doilea, etc., 1 dac textul din partea de editare nu este ales din list); TextChanged, SelectedIndexChanged evenimente de tratare a schimbrii textului prin introducerea direct a unui nou cuvnt sau prin alegerea unui obiect din list. MenuStrip Clasa System.Windows.Forms.MenuStrip principal al unei ferestre. Mod de folosire: corespunde meniului

se introduce o component de acest tip n fereastr; se editeaz meniul, direct n fereastr sau folosind proprietile; pentru separatori se introduce n cmpul Caption un minus ( ); literele care se vor a fi subliniate trebuie precedate de &; pentru implementarea metodei de tratare a unei opiuni din meniu se va face dublu-click pe aceasta (sau pe evenimentul Click n fereastra de proprieti).

Timer Clasa System.Windows.Forms.Timer ncapsuleaz funciile de temporizare din Windows. Cteva proprieti i evenimente: Tick evenimentul care va fi tratat o dat la un interval de timp; Interval intervalul de timp (n milisecunde) la care va fi executat codul corespunztor evenimentului Tick; Enabled indic dac timer-ul e activat sau nu (true / false).
55
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

string Este o clas care permite lucrul cu iruri de caractere. Exist operatorul +, care permite concatenarea irurilor:
string str1 = "Microsoft "; string str2 = "Word"; str1 = str1 + str2; // sau str1 += str2; => str1 == "Microsoft Word"

Clasa conine multe proprieti i metode utile, dintre care amintim: int Length lungimea irului; int IndexOf(...) poziia n ir la care apare prima dat un caracter sau un subir; string Substring(...) returneaz un subir; string Remove(int startIndex, int count) returneaz irul rezultat prin tergerea a count caractere din ir, ncepnd cu poziia startIndex; string[] Split(...) mparte irul n mai multe subiruri delimitate de anumite secvene de caractere.

O metod static a clasei este Format(...), care returneaz un ir de caractere corespunztor unui anumit format. Sintaxa este asemntoare cu cea a funciei printf din C. De exemplu:
double d = 0.5; string str = string.Format("Patratul numarului {0} este {1}", d, d * d);

Acelai rezultat s-ar fi putut obine astfel:


str = "Patratul numarului " + d.ToString() + " este " + (d * d).ToString();

Orice obiect are metoda ToString(), care convertete valoarea sa ntr-un ir. Pentru obiecte definite de programator, aceast metod poate fi suprascris. Dac n exemplul de mai sus d = 0.72654 i dorim s afim numerele numai cu 2 zecimale, metoda Format i dovedete utilitatea (figura 2.4).

56
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 2. Stilul de scriere a codului. Tratarea excepiilor. Interfaa grafic cu utilizatorul string str=string.Format("Patratul numarului {0:F2} este {1:F2}", d, d*d); MessageBox.Show(str);

Figura 2.4. Mesaj cu numere formatate

StringBuilder Majoritatea programatorilor utilizeaz de obicei clasa string cnd opereaz cu iruri de caractere. n cazul concatenrii unor iruri, folosirea clasei StringBuilder aduce o important cretere de performan. S considerm urmtorul bloc:
string listaNumere = ""; for (int i=0; i<1000; i++) listaNumere = listaNumere + " " + (i + 1).ToString();

n acest caz, se creeaz un nou obiect string la fiecare atribuire, adic de 1000 de ori! Codul echivalent folosind StringBuilder este urmtorul:
StringBuilder sbListaNumere = new StringBuilder(10000); for (int i = 0; i < 1000; i++) { sbListaNumere.Append(" "); sbListaNumere.Append((i+1).ToString()); } string listaNumere2 = sbListaNumere.ToString();

Pentru a avea acces la clasa StringBuilder, trebuie inclus namespace-ul System.Text la nceputul programului:
using System.Text;

Directivele using sunt asemntoare directivelor #include din C/C++. Namespace-urile sunt colecii de clase predefinite sau definite de
57
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

programator. Dac nu se dorete utilizarea unui namespace, clasa trebuie referit cu tot cu namespace. n cazul de fa:
System.Text.StringBuilder sbListaNumere = new System.Text.StringBuilder(10000);

Ca dezavantaje, trebuie s menionm c la iniializarea unui obiect StringBuilder performanele scad. De asemenea, sunt foarte multe operaii care nu se pot efectua cu StringBuilder, ci cu string. Pentru concatenarea a 2 iruri nu este nevoie de StringBuilder. Se poate recomanda utilizarea acestei clase dac e nevoie de concatenarea a cel puin 4 iruri de caractere. De asemenea, pentru creterea vitezei, trebuie s estimm lungimea final a irului (parametrul constructorului). Dac folosim constructorul vid sau lungimea estimat este mai mic dect n realitate, alocarea spaiului se face automat iar performana scade.

6. Elemente de C#
6.1. Clase pariale
n clasele corespunztoare ferestrelor, exist metode predefinite generate automat de mediul Visual Studio, care conin iniializarea controalelor grafice. Aceste metode sunt de obicei de dimensiuni mai mari i sunt separate de logica aplicaiei fiind plasate ntr-un alt fiier, numit *.Designer.cs. Definiia unei clase, structuri sau interfee se poate mpri n dou sau mai multe fiiere surs. Fiecare fiier surs conine o parte din definiia clasei i toate prile sunt combinate cnd aplicaia este compilat. Exist cteva situaii cnd este util mprirea definiiei clasei:

Cnd se lucreaz la proiecte mari, mprirea clasei n fiiere separate permite mai multor programatori s lucreze la ele simultan; Cnd se lucreaz cu surse generate automat, codul poate fi adugat clasei fr s mai fie nevoie de recrearea fiierului surs. Visual Studio folosete aceast cale cnd creeaz ferestrele Windows, codul wrapper pentru servicii web .a.m.d. Programatorul poate scrie codul care folosete aceste poriuni fr s mai fie nevoie de modificarea fiierului creat de Visual Studio.

58
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 2. Stilul de scriere a codului. Tratarea excepiilor. Interfaa grafic cu utilizatorul

Pentru a mpri definiia unei clase, se folosete cuvntul cheie partial, dup cum este prezentat mai jos:
public partial class Student { public void Learn() { } } public partial class Student { public void TakeExam() { } }

Modificatorul partial nu este valabil n declaraiile pentru funcii delegat sau enumerri.

6.2. Proprieti. Accesori


Proprietile sunt membri care furnizeaz un mecanism flexibil de citire, scriere, sau calculare de valori ale cmpurilor private. Ele pot fi folosite ca i cum ar fi membri publici, dar ele sunt de fapt metode speciale, care permit ca datele s fie accesate mai uor ns n acelai timp pstreaz sigurana i flexibilitatea metodelor. Proprietile combin aspecte specifice att cmpurilor ct i metodelor. Pentru utilizatorul unui obiect, o proprietate apare ca un cmp, deoarece accesul la proprietate necesit exact aceeai sintax. Pentru realizatorul clasei, o proprietate este format din unul sau dou blocuri de cod, reprezentnd un accesor get i/sau un accesor set. Blocul de cod pentru accesorul get este executat cnd proprietatea este citit, iar blocul de cod pentru accesorul set este executat cnd proprietii i este atribuit o valoare. O proprietate fr accesorul set este considerat doar pentru citire (read-only). O proprietate fr accesorul get este considerat doar pentru scriere (write-only). O proprietate cu ambii accesori este pentru citire i scriere (read-write).

59
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

6.2.1. Accesorul get Corpul accesorului get este similar cu cel al unei metode i trebuie s returneze o valoare de tipul proprietii. Execuia accesorului get este echivalent cu citirea valorii cmpului corespunztor. n urmtorul exemplu, este prezentat un accesor get ce ntoarce valoarea unui cmp privat _name:
class Person { private string _name; public string Name { get { return _name; } } }

// cmp // proprietate

Din exteriorul clasei, citirea valorii proprietii se realizeaz astfel:


Person p1 = new Person(); Console.Write(p1.Name); // se apeleaz accesorul get

Accesorul get trebuie s se termine cu instruciunea return sau throw, iar fluxul de control nu poate depi corpul accesorului. Cnd se ntoarce doar valoarea unui cmp privat i sunt permise optimizrile, apelul ctre accesorul get este tratat inline de ctre compilator n aa fel nct s nu se piard timp prin efectuarea unui apel de metod. Totui, un accesor get virtual nu poate fi tratat inline ntruct compilatorul nu tie n timpul compilrii ce metod va fi de fapt apelat n momentul rulrii. Schimbarea strii unui obiect utiliznd accesorul get nu este recomandat. De exemplu, urmtorul accesor produce ca efect secundar schimbarea strii obiectului de fiecare dat cnd este accesat cmpul _number.

60
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 2. Stilul de scriere a codului. Tratarea excepiilor. Interfaa grafic cu utilizatorul private int _number; public int Number { get { return _number++; } }

// !!! nerecomandat

Accesorul get poate fi folosit fie ca s returneze valoarea unui cmp, fie s o calculeze i apoi s o returneze. De exemplu:
class Student { private string _name; public string Name { get { return _name != null ? _name : "NA"; } } }

n secvena de cod anterioar, dac _name este null, proprietatea va ntoarce totui o valoare, i anume NA (engl. No Account). 6.2.2. Accesorul set Accesorul set (numit i mutator) este similar cu o metod ce ntoarce void. Folosete un parametru implicit numit value (valoare), al crui tip este tipul proprietii. n exemplul urmtor, este adugat un accesor set proprietii Name:

61
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C# class Person { private string _name; public string Name { get { return _name; } set { _name = value; } } }

Cnd se atribuie o valoare proprietii, este apelat accesorul set cu un argument ce furnizeaz noua valoare. De exemplu:
Person p1 = new Person(); p1.Name = "Joe"; // se apeleaz accesorul set cu value = "Joe"

6.2.3. Aspecte mai complexe ale lucrului cu proprieti n exemplul urmtor, clasa TimePeriod reine o perioad de timp n secunde, dar are o proprietate numit Hours care permite unui client s lucreze cu timpul n ore.
class TimePeriod { private double _seconds; public double Hours { get { return _seconds / 3600; } set { _seconds = value * 3600; } } }

62
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 2. Stilul de scriere a codului. Tratarea excepiilor. Interfaa grafic cu utilizatorul class Program { static void Main() { TimePeriod t = new TimePeriod(); // atribuirea proprietii Hours determin apelul accesorului set t.Hours = 24; // evaluarea proprietii Hours determin apelul accesorului get Console.WriteLine("Timpul in ore: " + t.Hours); } }

n mod implicit, accesorii au acceai vizibilitate, sau nivel de acces cu al proprietii creia i aparin. Totui, uneori li se poate restriciona accesul. De obicei, aceasta implic restricionarea accesibilitii accesorului set, n timp ce accesorul get rmne public. De exemplu:
public string Name { get { return _name; } protected set { _name = value; } }

Aici, accesorul get primete nivelul de accesibilitate al proprietii nsi, public n acest caz, n timp ce accesorul set este restricionat n mod explicit aplicnd modificatorul de acces protected. Proprietile au mai multe utilizri: pot valida datele nainte de a permite o modificare, pot returna date cnd acestea sunt de fapt provenite din alte surse, precum o baz de date, pot produce o aciune cnd datele sunt modificate, cum ar fi invocarea unui eveniment sau schimbarea valorii altor cmpuri. n exemplul urmtor, Month este o proprietate:

63
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C# public class Date { private int _month = 7; public int Month { get { return _month; } set { if ((value > 0) && (value < 13)) { _month = value; } } } }

Aici, accesorul set garanteaz c valoarea cmpului _month este ntre 1 i 12. Locaia real a datelor proprietii este de obicei denumit memorie auxiliar (engl. backing store). Marea majoritate a proprietilor utilizeaz n mod normal cmpuri private ca memorie auxiliar. Cmpul este marcat privat pentru a se asigura faptul c nu poate fi accesat dect prin apelarea proprietii. O proprietate poate fi declarat static folosind cuvntul cheie static. n acest fel proprietatea devine disponibil apelanilor oricnd, chiar dac nu exist nicio instan a clasei. Spre deosebire de cmpuri, proprietile nu sunt clasificate ca variabile i de aceea nu se poate transmite o proprietate ca parametru ref sau out. Important! Exist instrumente care genereaz automat proprieti read-write pentru toate cmpurile. Dac ntr-o clas exist multe cmpuri, trebuie s ne ntrebm dac toate acestea trebuie s fie accesibile din exterior. Nu are sens ca toate cmpurile private ale unei clase s fie expuse n afar, chiar i prin intermediul proprietilor.

64
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 2. Stilul de scriere a codului. Tratarea excepiilor. Interfaa grafic cu utilizatorul

7. Aplicaii
7.1. Realizai interfaa grafic a unei aplicaii Windows pentru rezolvarea de ecuaii polinomiale de gradul I i II, precum i de ecuaii trigonometrice simple (figura 2.5).

Figura 2.5. Exemplu de rezolvare

7.2. Creai clasele pentru rezolvarea celor dou tipuri de ecuaii (figura 2.6). Se vor arunca dou tipuri de excepii, conform structurii de mai jos. Fiind dou tipuri diferite de ecuaii, vom avea o interfa IEquation cu metoda Solve, din care vor fi derivate PolyEquation i TrigEquation. n clasa principal, evenimentul de tratare a apsrii butonului Calculeaza va testa tipul de ecuaie. Pentru o ecuaie polinomial, va citi coeficienii ecuaiei i va instania un obiect corespunztor:
IEquation eq = new PolyEquation(x2, x1, x0); textBoxSolutie.Text = eq.Solve();

Pentru o ecuaie trigonometric, depinznd de tipul de funcie trigonometric:


eq = new TrigEquation(TrigEquation.TrigonometricFunction.Sin, arg); textBoxSolutie.Text = eq.Solve();

65
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

Figura 2.6. Exemplu de rezolvare: clasele soluiei

Fiecrui tip de ecuaie i va corespunde propria clas de excepie: PolyException, respectiv TrigException. Pentru ecuaia polinomial se vor considera urmtoarele excepii:

pentru pentru

: O infinitate de soluii; : Nicio soluie.

Pentru ecuaia trigonometric, excepia Argument invalid va fi | aruncat cnd | , ns numai pentru funciile arcsin i arccos. n evenimentul butonului vom avea un singur bloc try, urmat de trei blocuri catch: pentru cele dou tipuri de excepie, precum i pentru excepiile generice, rezultate de exemplu la ncercarea de a citi coeficienii, dac utilizatorul introduce caractere nenumerice. Indicaie: codul pentru rezolvarea ecuaiei polinomiale este prezentat n continuare, unde :

66
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 2. Stilul de scriere a codului. Tratarea excepiilor. Interfaa grafic cu utilizatorul if (_x2 == 0) { _eqType = EquationType.FirstDegree; // soluie: -_x0 / _x1 } else if (delta > 0) { double sqrtDelta = Math.Sqrt(delta); double sol1 = (-_x1 + sqrtDelta) / (2.0 * _x2); double sol2 = (-_x1 - sqrtDelta) / (2.0 * _x2); // soluii: sol1, sol2 } else if (delta == 0) { double sol = (-_x1) / (2.0 * _x2); // soluie: sol } else { double rsol = -_x1 / (2.0 * _x2); double isol = Math.Sqrt(-delta) / (2.0 * _x2); // soluii: rsol isol }

Atenie: scopul laboratorului este lucrul cu excepii, nu rezolvarea propriu-zis a ecuaiilor! 7.3. Eliminai blocurile try-catch din clasa principal a aplicaiei i efectuai tratarea excepiilor pe firul de execuie n metoda Main.

67
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

68
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 3

Reutilizarea codului cu ajutorul DLL-urilor


1. Obiective 2. Bibliotecile legate dinamic 3. Crearea DLL-urilor n C# 4. Grafic n C# 5. Aplicaii

1. Obiective
Obiectivele capitolului 3 sunt urmtoarele: Descrierea DLL-urilor; Legarea static a DLL-urilor .NET, cea mai simpl i folosit form; Legarea dinamic a DLL-urilor .NET, util pentru crearea plug-in-urilor; Prezentarea unor aspecte privind grafica n C#.

2. Bibliotecile legate dinamic


Bibliotecile legate dinamic (engl. Dynamic Link Libraries, DLL), reprezint implementarea Microsoft a conceptului de bibliotec partajat (engl. shared library). n trecut, DLL-urile au dat dezvoltatorilor posibilitatea de a crea biblioteci de funcii care puteau fi folosite de mai multe aplicaii. nsui sistemul de operare Windows a fost proiectat pe baza DLL-urilor. n timp ce avantajele modulelor de cod comun au extins oportunitile dezvoltatorilor, au aprut de asemenea probleme referitoare la actualizri i revizii. Dac un program se baza pe o anumit versiune a unui DLL i alt program actualiza acelai DLL, de multe ori primul program nceta s mai funcioneze corect. Pe lng problemele legate de versiuni, dac se dorea dezinstalarea unei aplicaii, se putea terge foarte uor un DLL care era nc folosit de un alt program. Soluia propus de Microsoft a fost introducerea posibilitii de a urmri folosirea DLL-urilor cu ajutorul registrului, ncepnd cu Windows
69
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

95. Se permitea unei singure versiuni de DLL s ruleze n memorie la un moment dat. Cnd era instalat o nou aplicaie care folosea un DLL existent, se incrementa un contor. La dezinstalare, contorul era decrementat i dac nicio aplicaie nu mai folosea DLL-ul, atunci acesta putea fi ters. Apare ns o alt problem deoarece cnd un DLL este ncrcat, Windows va folosi versiunea ce ruleaz pn cnd nicio aplicaie nu o mai folosete. Astfel, chiar dac DLL-ul sistemului este n regul, sau o aplicaie are o copie local pe care se lucreaz, cnd aplicaia precedent a pornit cu o versiune incompatibil, atunci noua aplicaie nu va merge. Aceast problem se poate manifesta n situaii precum urmtoarele: o aplicaie nu funcioneaz atunci cnd ruleaz o alt aplicaie sau, i mai ciudat, o aplicaie nu funcioneaz dac o alt aplicaie a rulat (dar nu mai ruleaz neaprat n prezent). Dac aplicaia A ncarc o bibliotec incompatibil sau corupt, atunci aplicaia B lansat folosete aceast bibliotec. Aceast versiune va sta n memorie chiar dup ce aplicaia A nu mai exist (att timp ct aplicaia B nc ruleaz), deci aplicaia B s-ar putea s nceteze s funcioneze din cauza aplicaiei A, chiar dac aceasta nu mai ruleaz. O a treia aplicaie C poate s eueze (ct vreme aplicaia B nc ruleaz) chiar dac este pornit dup ce aplicaia A a fost nchis. Rezultatul s-a numit infernul DLL (engl. DLL hell). Rezolvarea infernului DLL a fost unul din scopurile platformei .NET. Aici pot exista mai multe versiuni ale unui DLL ce ruleaz simultan, ceea ce permite dezvoltatorilor s adauge o versiune care funcioneaz la programul lor fr s se ngrijoreze c un alt program va fi afectat. Modul n care .NET reuete s fac aceasta este prin renunarea la folosirea registrului pentru a lega DLL-urile de aplicaii i prin introducerea conceptului de assembly.

3. Crearea DLL-urilor n C#
Din fereastra corespunztoare File New Project, se alege tipul proiectului Class Library (figura 3.1). n namespace-ul proiectului pot fi adugate mai multe clase. n acest caz, din exterior fiecare clas va fi accesat ca Namespace.ClassName. Dac se elimin namespace-ul, clasa va fi accesat direct cu numele clasei: ClassName. Spre deosebire de o aplicaie executabil, aici nu va exista o metod Main, deoarece DLL-ul este numai o bibliotec de funcii utilizabile din alte programe executabile.

70
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 3. Reutilizarea codului cu ajutorul DLL-urilor

Figura 3.1. Crearea unui proiect de tip Class Library (DLL)

Figura 3.2. Adugarea unei referine la un DLL

71
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

3.1. Legarea static


Dup ce s-a creat un proiect corespunztor unei aplicaii executabile, din Project Add Reference, se selecteaz de pe harddisk n tab-page-ul Browse fiierul DLL care trebuie adugat n proiect. n continuare, n program vor fi utilizate ca atare toate funciile din DLL (figura 3.2). S considerm urmtorul exemplu: avem ntr-un DLL numit Operatii.dll o clas Putere n namespace-ul Matematica avnd o metod double Patrat(double x) care returneaz valoarea parametrului ridicat la ptrat. Mai nti, se va cuta i selecta fiierul Operatii.dll de pe harddisk. Apoi, ntr-o metod din clasa programului principal, se va apela direct metoda de ridicare la putere:
double a = Matematica.Putere.Patrat(5.5);

3.2. Legarea dinamic


Legarea static presupune c se cunoate ce DLL va trebui ncrcat nainte de executarea programului. Exist totui situaii n care acest lucru este imposibil: de exemplu, dac o aplicaie necesit o serie de plug-in-uri, acestea pot fi adugate sau terse, iar aplicaia principal trebuie s determine dup lansarea n execuie cu ce DLL-uri poate lucra. Un alt avantaj este faptul c programatorul poate testa existena unui anumit DLL necesar i poate afia un mesaj de eroare i eventual o modalitate de corectare a acesteia. C# permite ncrcarea dinamic a DLL-urilor. S considerm tot exemplul anterior. Apelul metodei de ridicare la ptrat se face n modul urmtor:
// se ncearc ncrcarea DLL-ului Assembly a = Assembly.Load("Operatii"); // se identific tipul (clasa) care trebuie instaniat // dac n clasa din DLL exist un namespace, // se folosete numele complet al clasei din assembly, incluznd namespace-ul Type t = a.GetType("Matematica.Putere"); // se identific metoda care ne intereseaz MethodInfo mi = t.GetMethod("Patrat");

72
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 3. Reutilizarea codului cu ajutorul DLL-urilor // se creeaz o instan a clasei dorite // aici se apeleaz constructorul implicit object o = Activator.CreateInstance(t); // definim un vector de argumente pentru a fi trimis metodei // metoda Ptrat are numai un argument de tip double object[] args = new object[1]; double x = 5.5; args[0] = x; // apelul efectiv al metodei i memorarea rezultatului double result = (double)mi.Invoke(o, args);

Acesta este modul general de ncrcare. Este obligatorie tratarea excepiilor care pot aprea datorit unei eventuale absene a DLL-ului sau a ncrcrii incorecte a unei metode. De aceea, fluxul de mai sus va trebui mprit n mai multe blocuri care s permit tratarea excepiilor, ncrcarea o singur dat a bibliotecii i apelarea de cte ori este nevoie a metodelor dorite. Dac se apeleaz dinamic o metod static, se folosete null n loc de obiectul o. La nceputul programului, dac avem o aplicaie Windows, n evenimentul Load al ferestrei trebuie s existe un bloc de tipul:
private void Form1_Load(object sender, EventArgs e) { try { LoadOperatiiPutere(); } catch (Exception exc) { MessageBox.Show(exc.Message, "Exceptie DLL"); Close(); } }

73
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

Metoda care ncarc efectiv DLL-ul este:


private void LoadOperatiiPutere() { Type t = null; try { Assembly a = Assembly.Load("Operatii"); t = a.GetType("Matematica.Putere"); } catch (Exception) { throw new Exception("Operatii.dll nu poate fi incarcat"); } _miPatrat = t.GetMethod("Patrat"); if (_miPatrat == null) throw new Exception("Metoda Patrat din Operatii.dll nu poate fi accesata"); _objPutere = Activator.CreateInstance(t); }

este:

Metoda clasei din programul executabil care realizeaz apelul efectiv

private double MyOperatiiPutere(double x) { object[] args = new object[1]; args[0] = x; return (double)_miPatrat.Invoke(_objPutere, args); }

Pentru compilarea codului de mai sus este necesar includerea n program a namespace-ului System.Reflection.

3.3. Depanarea unui DLL


Deoarece un DLL nu este direct executabil, exist dou metode pentru dezvoltarea i depanarea unei astfel de componente. Abordarea cea mai simpl este crearea unei aplicaii executabile, de cele mai multe ori de tip consol n cazul n care DLL-ul va conine funcii
74
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 3. Reutilizarea codului cu ajutorul DLL-urilor

de calcul i nu grafice. n proiect va exista namespace-ul DLL-ului cu toate clasele aferente, iar n plus o clas cu o metod Main, din care se vor putea apela i depana metodele din DLL. La sfrit, dup ce DLL-ul este corect, se poate exclude clasa cu Main i se poate recompila proiectul ca DLL: Project Properties Application Output type. Alternativ, se poate crea un nou proiect de tip Class library n care se va copia codul DLL-ului. A doua metod este includerea a dou proiecte ntr-o soluie n Visual Studio. Un proiect va fi DLL-ul iar cellalt proiect va fi unul executabil. Din proiectul executabil trebuie adugat referina la DLL. n consecin, fiierul dll rezultat din compilare va fi copiat automat n directorul fiierului exe.

4. Grafic n C#
Pentru lucrul n mod grafic, C# pune la dispoziia programatorului o clas numit Graphics. Pentru a transla suprafaa de desenare n cadrul ferestrei, se poate folosi un obiect de tip PictureBox, care va fi plasat acolo unde se dorete. Important! Desenarea n fereastr, ntr-un PictureBox sau n orice alt control trebuie fcut numai n evenimentul Paint al controlului respectiv. n caz contrar, cnd fereastra este minimizat sau cnd controlul este acoperit de alte ferestre, desenul se pierde. Evenimentul Paint conine un parametru de tipul:
System.Windows.Forms.PaintEventArgs e

Suprafaa grafic a controlului va fi n acest caz e.Graphics, care conine metodele de desenare. Majoritatea controalelor au implementat un eveniment Paint. n afara acestuia, suprafaa de desenare poate fi identificat prin metoda CreateGraphics, care returneaz un obiect de tip Graphics. n cele ce urmeaz, vom aminti unele elemente de baz, care pot fi folosite n program ca atare (totui, pentru aprofundarea acestor cunotine, se pot consulta alte manuale sau documentaia MSDN). Deoarece majoritatea metodelor sunt suprancrcate, vom da cte un exemplu simplu de utilizare pentru fiecare situaie.

75
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

Desenarea unei linii


e.Graphics.DrawLine(Pen pen, int x1, int y1, int x2, int y2)

Primul parametru precizeaz culoarea i stilul de desenare a liniei. Se poate declara i folosi un nou obiect de tip Pen (Pen pen = new Pen(...)), ns pentru linii continue i culori predefinite se poate utiliza enumerarea Pens. De exemplu:
e.Graphics.DrawLine(Pens.Black, 10, 10, 20, 40);

Desenarea unui dreptunghi i a unei elipse


e.Graphics.DrawRectangle(Pen pen, int x, int y, int latime, int inaltime)

Deseneaz conturul unui dreptunghi, cu un anumit stil i culoare, folosind coordonatele unui vrf i respectiv limea i nlimea sa. Pentru umplerea unui dreptunghi cu un anumit model i culoare, se folosete metoda:
e.Graphics.FillRectangle(Brush b, int x, int y, int latime, int inaltime)

Ca i n cazul unui Pen, se poate declara un nou obiect de tip Brush, de exemplu:
Brush b = new SolidBrush(Color.Blue);

sau se poate folosi enumerarea Brushes, care presupune c stilul de umplere va fi solid (compact). Un dreptunghi alb cu contur negru se va desena astfel:
e.Graphics.FillRectangle(Brushes.White, 0, 0, 10, 20); e.Graphics.DrawRectangle(Pens.Black, 0, 0, 10, 20);

n mod analog se folosesc metodele DrawEllipse i FillEllipse. Afiarea unui text n mod grafic
DrawString (string s, Font font, Brush brush, int x, int y) 76
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 3. Reutilizarea codului cu ajutorul DLL-urilor

Primul parametru este textul care trebuie afiat. Al doilea parametru reprezint corpul de liter cu care se va desena irul de caractere. De exemplu:
Font font = new Font("Arial", 10);

Al treilea parametru este utilizat pentru trasarea efectiv a textului (vezi paragraful despre desenarea unui dreptunghi i a unei elipse). Ultimii doi parametri sunt coordonatele ecran. Double-buffering automat Deoarece funciile grafice sunt n general lente, pentru desene suficient de complexe sau animaii, unde se presupune tergerea unor elemente i afiarea altora, ecranul pare s clipeasc (engl. flickering). O soluie este desenarea tuturor elementelor ntr-o zon de memorie, de exemplu un Bitmap, i apoi afiarea direct a acestuia pe ecran. Aceast afiare presupune de obicei doar copierea unor informaii dintr-o zon de memorie n alta, fiind deci foarte rapid. Deoarece se folosesc dou zone de memorie, aceast tehnic se numete double-buffering. n anumite situaii, se pot folosi mai multe zone de memorie. n C# se poate face automat double-buffering, prin introducerea unei linii precum urmtoarea (de obicei, dar nu obligatoriu) n constructorul ferestrei:
SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.DoubleBuffer | ControlStyles.UserPaint, true);

Versiunea 2.0 a platformei .NET (cu Visual Studio 2005) a introdus proprietatea DoubleBuffered pentru obiectele Form.

5. Aplicaii
5.1. Realizai un DLL numit Prim care s conin o clas cu o metod care testeaz dac un numr natural, primit ca parametru, este prim. Not: 1 nu este numr prim.

77
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

5.2. Realizai un program executabil care testeaz conjectura lui Goldbach: orice numr par mai mare sau egal ca 4 poate fi scris ca sum de 2 numere prime i orice numr impar mai mare sau egal ca 7 poate fi scris ca sum de 3 numere prime (figura 3.3). Va fi folosit funcia de test pentru numere prime din Prim.dll. Legarea se va face static.

Figura 3.3. Exemplu de rezolvare

5.3. Modificai Prim.dll prin adugarea unei metode int NumaraPrime(int n), care calculeaz numrul numerelor prime mai mici sau egale cu . Verificai c Suma.exe se execut corect dup modificarea DLL-ului. 5.4. Realizai un program executabil care ncarc dinamic biblioteca Prim.dll i apeleaz metoda NumaraPrime. 5.5. Tem pentru acas. Realizai un program executabil care s afieze graficul funciei: = numrul de numere prime , precum i o aproximare a acestui numr, de forma: > 0.

Pentru calculul exact, se va utiliza metoda int NumaraPrime(int n) din Prim.dll. Pentru aproximare, se va crea un DLL numit Aproximare, cu o clas cu acelai nume care s conin o metod double XLogX(double x).

78
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 3. Reutilizarea codului cu ajutorul DLL-urilor

Legarea se va face dinamic. Verificai tratarea excepiilor n cazul utilizrii unui DLL cu o semntur incorect a metodei XLogX. Indicaii. Pentru fiecare metod din DLL-uri, este util definirea unei metode corespunztoare n programul principal. De exemplu, pentru metoda EstePrim din Prim.dll, se poate crea o metod de tipul:
private bool MyPrimEstePrim(int n)

care s apeleze metoda EstePrim i s returneze rezultatul. n continuare, n program se va apela direct metoda MyPrimEstePrim. ncrcarea DLL-ului trebuie fcut o singur dat, la pornirea programului, chiar dac apelul metodelor se va face ori de cte ori este necesar. Cele dou funcii nu se suprapun, doar forma lor este asemntoare. De aceea, cele dou grafice trebuie scalate diferit pe axa Y (figura 3.4).

Figura 3.4. Exemplu de rezolvare

79
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

80
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 4

Documentarea unui proiect. Fiiere de ajutor


1. Obiective 2. Crearea de fiiere de ajutor 3. Activarea unui fiier de ajutor prin program 4. Generarea automat a documentaiei API 5. Comentariile 6. Lucrul cu fiiere n C#: ncrcare, salvare 7. Aplicaii

1. Obiective
Obiectivele principale ale capitolului 4 sunt urmtoarele: Crearea de fiiere de ajutor (help) n formatele HLP i CHM ; Activarea unui fiier de ajutor dintr-un program C#; Generarea automat a documentaiei API a unei soluii C# cu ajutorul utilitarului NDoc. n plus, ne propunem: S oferim o serie de recomandri privind comentarea unui program; S prezentm utilizarea dialogurilor de ncrcare i salvare, precum i o modalitate simpl de a lucra cu fiiere n C#; S utilizm o clas care poate rezolva ptrate magice de orice dimensiune (att de dimensiune impar ct i de dimensiune par).

2. Crearea de fiiere de ajutor


2.1. Crearea de fiiere HLP
Un utilitar gratuit pentru realizarea de fiiere HLP este Microsoft Help Workshop (figura 4.1). Acesta creeaz fiiere HLP pe baza unui
81
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

document Rich Text Format, RTF, editat dup anumite convenii, corespunztoare opiunilor fiierelor de ajutor. Subiectele din help sunt asociate n general cu un identificator unic. Acesta se insereaz printr-o not de subsol (engl. footnote) cu caracterul # naintea titlului paginii respective. Deschiderea unei anumite pagini de ajutor, att din fiierul cuprins, ct i dintr-un program, se face pe baza acestui identificator. Paginile sunt desprite cu separator de pagin (engl. page break).

Figura 4.1. Microsoft Help Workshop

Fiierul de ajutor propriu-zis poate fi nsoit de un fiier cuprins, cu formatul urmtor:


:Base Exemplu.hlp :Title Exemplu de fisier .hlp :Index=Exemplu.hlp 1 Capitolul 1 2 Pagina 1=Topic_id1 2 Pagina 2=Topic_id2 1 Capitolul 2 2 Pagina 3=Topic_id3

82
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 4. Documentarea unui proiect. Fiiere de ajutor

Base reprezint numele fiierului de ajutor, titlul determin textul ce va aprea pe bara ferestrei help-ului, iar indexul precizeaz fiierul de unde se va face indexarea (n cazul nostru, acelai fiier). n continuare, se descrie structura help-ului ntr-o manier arborescent. Numerele din faa denumirilor de capitole reprezint nivelul n arbore al subiectului respectiv (figura 4.2).

Figura 4.2. Cuprinsul unui fiier HLP

Se observ c legtura la paginile corespunztoare se face pe baza identificatorului de subiect, topic id. Pentru ca utilizatorul s navigheze uor prin help, sunt disponibile opiuni de indexare i cutare a cuvintelor cheie. n cazul indexului, cuvintele cheie sunt desemnate printr-o not de subsol marcat K. Pagina de index afieaz lista cuvintelor cheie definite pentru fiecare subiect (figura 4.3).

83
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

Figura 4.3. Indexul unui fiier HLP

Figura 4.4. Pagina de cutare ntr-un fiier HLP


84
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 4. Documentarea unui proiect. Fiiere de ajutor

n pagina de cutare Find (figura 4.4), help-ul genereaz automat o list cu toate cuvintele gsite. Utilizatorul poate introduce un anumit cuvnt, sau mai multe, i afl n ce pagini apare acesta. Titlurile de subiecte care apar n lista de jos sunt determinate de o not de subsol marcat cu $ n fiierul RTF. Dac se dorete includerea unor imagini, acestea sunt pur i simplu inserate n fiierul RTF i vor aprea n mod automat i n help. O alt opiune util este includerea de texte pop-up, n situaii n care explicarea unui termen sau a unui concept este suficient de scurt i nu necesit utilizarea unei pagini noi (figura 4.5).

Figura 4.5. Text pop-up ntr-un fiier HLP

Acest format presupune inserarea unui text ascuns n fiierul RTF. Dac editorul folosit este Microsoft Word, atunci trebuie s activm mai nti opiunea de vizualizare a informaiilor ascunse, prin combinaia de taste CTRL+* sau CTRL+SHIFT+8. Textul link va fi subliniat i imediat dup el va fi introdus un identificator pentru fereastra mic ce va aprea. Identificatorul va fi scris cu litere ascunse, ceea ce se poate realiza din meniul Format Font... Hidden. S presupunem c identificatorul se numete POPUP. ntr-o alt pagin se va scrie textul care se dorete s apar (n cazul nostru: Textul apare ntr-o fereastr mic). n faa sa, va fi inserat o not

85
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

de subsol marcat cu #, iar coninutul notei va fi identificatorul menionat anterior, POPUP. Pentru realizarea unei legturi la alt pagin, se va sublinia dublu textul corespunztor legturii, care va fi urmat de identificatorul subiectului paginii la care se vrea s se sar.

2.2. Crearea de fiiere CHM


Un utilitar gratuit pentru realizarea de fiiere CHM (Compiled HTML) este HTML Help Workshop (figura 4.6).

Figura 4.6. Microsoft HTML Help Workshop

Ideea care st la baza acestui format este transformarea unui site web sau a unui grup de pagini HTML ntr-un singur fiier, cu opiuni de navigare i cutare. Pentru a realiza un astfel de fiier, trebuie create mai nti paginile HTML cu informaiile utile. n tab-page-ul Project se apas al doilea buton din stnga, Add/Remove topic files. Este suficient includerea paginii de index, de la care se presupune c exist legturi ctre celelalte pagini. Se creeaz apoi cte un fiier Contents i Index.

86
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 4. Documentarea unui proiect. Fiiere de ajutor

Figura 4.7. Crearea cuprinsului unui fiier CHM

Figura 4.8. Crearea intrrilor de index ale unui fiier CHM

87
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

n tab-page-ul Contents (figura 4.7), se pot insera subiectele corespunztoare unor anumite pagini. Pentru aceasta se folosesc butoanele din stnga Insert a heading (un nod n arbore) i Insert a page (o frunz). n mod analog se definesc i intrri de index, care pot fi asociate cu una sau mai multe pagini (figura 4.8). Dac o intrare de index are mai multe pagini asociate, la cutare rezultatul va fi de forma celui prezentat n figura 4.9.

Figura 4.9. Rezultatele cutrii ntr-un fiier CHM

Pentru generarea automat a opiunii de cutare n lista de cuvinte a paginilor, se apas primul buton din stnga din tab-page-ul Project, numit Change project options, iar n pagina Compiler se bifeaz csua Compile full-text search information.

3. Activarea unui fiier de ajutor prin program


3.1. Process.Start
Cel mai simplu mod de deschidere a unui fiier de ajutor este printr-un apel la sistemul de operare. n C# apelul este de forma:
System.Diagnostics.Process.Start("nume-fisier");

3.2. HelpProvider
O alt modalitate este utilizarea clasei specializate HelpProvider. Se introduce n Form un astfel de obiect i apoi din fereastra de proprieti se
88
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 4. Documentarea unui proiect. Fiiere de ajutor

seteaz numele fiierului CHM asociat n cmpul HelpNamespace. Desigur aceast operaie i cele descrise n continuare pot fi fcute i prin program. Apoi, pentru fiecare control din fereastr pentru care dorim s apar help-ul atunci cnd apsm tasta F1, trebuie s modificm urmtoarele proprieti: Show help on help provider: true; Help navigator on help provider: locul unde vrem s se deschid help-ul: la pagina de cuprins, la pagina de index, de cutare sau la o pagin specificat de programator; Help keyword on help provider: dac pentru controlul respectiv avem o anumit pagin care trebuie deschis, Help navigator on help provider va lua valoarea Topic iar n Help keyword on help provider se va introduce calea ctre pagina care trebuie deschis, relativ la fiierul CHM. De exemplu, dac fiierul este obinut prin compilarea unui director numit web, n care se gsete un document pag1.htm, care trebuie deschis acum, n acest cmp se va introduce: web\pag1.htm.

3.3. Help
Pentru activarea unui fiier de ajutor CHM se poate folosi i clasa Help. Aceasta are un numr de metode statice specifice, precum ShowHelp, ShowHelpIndex, ShowPopup. Pentru acelai exemplu de fiier CHM vom avea: Help.ShowHelp(this, "Exemplu.chm") o deschide fiierul Exemplu.chm; Help.ShowHelp(this, "Exemplu.chm", "web/pag1.htm") o deschide pagina solicitat din acelai fiier; Help.ShowHelpIndex(this,"Exemplu.chm") o deschide pagina de index a fiierului Exemplu.chm; Help.ShowPopup(this, "Pop-up window", new Point(Cursor.Position.X, Cursor.Position.Y)) o deschide o fereastr de pop-up cu textul dorit la coordonatele curente ale mouse-ului.

89
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

4. Generarea automat a documentaiei API


NDoc genereaz documentaie pentru Interfaa de Programare a Aplicaiei (engl. Application Programming Interface, API) pe baza assembly-urilor .NET i a fiierelor de documentaie XML generate de compilatorul C#. NDoc poate genera documentaia n diferite formate, precum help-ul HTML n stil MSDN, CHM, formatul Visual Studio .NET (HTML Help 2), sau stilul de pagini web de tip MSDN online. Documentaia XML se realizeaz automat prin includerea n codul surs a comentariilor triple: linii care ncep cu /// i care preced un tip definit de utilizator cum ar fi: namespace-uri, clase, interfee sau membrii precum cmpuri, metode, proprieti sau evenimente. Pentru a genera automat fiierul XML, trebuie setat calea ctre acesta n Project Properties Build Output XML documentation file (figura 4.10).

Figura 4.10. Generarea automat a unui fiier de documentaie XML

90
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 4. Documentarea unui proiect. Fiiere de ajutor

Figura 4.11. Utilitarul NDoc

n programul NDoc, se adaug assembly-ul pentru care se va crea documentaia i se seteaz proprietile proiectului ce anume va fi inclus n documentaie. De exemplu, o API pentru un utilizator extern nu va documenta metodele private, deoarece acestea oricum nu vor putea fi accesate de utilizator. Pentru a genera o referin de uz intern, se pot include i aceste metode prin setarea proprietii respective. Tot aici se alege titlul documentaiei i formatul acesteia (Documentation type). Apoi se apas butonul Build Docs din bara de instrumente (figura 4.11). Va rezulta documentaia n formatul ales (figura 4.12).

91
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

Figura 4.12. Documentaie API creat cu NDoc

5. Comentariile
n cele ce urmeaz, se prezint civa pai de baz pentru a mbunti calitatea comentariilor. Trebuie s se explice DE CE, nu CUM. Comentariile nu trebuie s descrie cum lucreaz programul; se poate vedea aceasta citind codul, care trebuie scris clar i inteligibil. Trebuie n schimb s ne concentrm asupra explicrii motivelor pentru care s-a scris n acest fel sau ce ndeplinete n final un bloc de instruciuni. Trebuie verificat dac se scrie constant actualizarea structurii StudentList din StRegistry sau memorarea informaiilor despre obiectele Student pentru a fi folosite mai trziu. Cele dou formulri sunt echivalente, dar a doua precizeaz scopul codului pe cnd prima spune doar ce face codul. n timpul ntreinerii acelei pri din cod, motivele pentru care aceasta exist se vor schimba mult mai rar dect modalitile concrete de
92
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 4. Documentarea unui proiect. Fiiere de ajutor

implementare. ntreinerea celui de-al doilea tip de comentarii este deci mult mai uoar. Comentariile bune explic de ce, nu cum. De asemenea, se pot folosi comentarii pentru a explica alegerea unei anumite implementri. Dac exist dou strategii de implementare posibile i se opteaz asupra uneia din ele, atunci se pot aduga comentarii pentru a explica motivele alegerii. Nu trebuie descris codul. Comentariile descriptive inutile sunt evidente: ++i; // incrementeaz i. Unele pot s fie mult mai subtile: comentarii descriptive lungi ale unui algoritm complex, urmat de implementarea algoritmului. Nu este nevoie s se rescrie laborios codul n limbaj natural dect dac se documenteaz un algoritm complex care ar fi altfel impenetrabil. Nu trebuie duplicat codul n comentarii. Nu trebuie nlocuit codul. Dac exist comentarii care specific ceva ce s-ar putea aplica prin nsui limbajul de programare, de exemplu aceast variabil ar trebui accesat doar de ctre clasa A, atunci acest deziderat trebuie exprimat printr-o sintax concret. Dac ne gsim n situaia n care scriem comentarii pentru a explica cum lucreaz un algoritm complex, atunci trebuie s ne oprim. Este bine s documentm codul, dar ar fi i mai bine dac am putea face codul sau algoritmul mai clar: Dac se poate, codul trebuie mprit n cteva funcii bine denumite pentru a reflecta logica algoritmului; Nu trebuie scrise comentarii care s descrie folosirea unei variabile; aceasta trebuie redenumit. Comentariile pe care vrem s le scriem ne spun deseori care ar trebui s fie numele variabilei; Dac se documenteaz o condiie care ar trebui s fie ntotdeauna ndeplinit, poate ar trebui s se scrie o aseriune de testare a unitilor (mai multe detalii se vor vedea n capitolele 13 i 14); Nu este nevoie de optimizri premature care pot obscuriza codul.

Cnd ne aflm n situaia de a scrie comentarii dense pentru a explica codul, trebuie sa facem un pas napoi, ntruct s-ar putea s existe o problem mai mare care trebuie rezolvat. Codul neateptat trebuie documentat. Dac o parte din cod este neobinuit, neateptat sau surprinztoare, trebuie documentat cu un comentariu. Ne va fi mult mai uor mai trziu cnd vom reveni, uitnd totul

93
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

despre problem. Dac exist soluii alternative specifice (workarounds), acestea trebuie menionate n comentarii. Comentariile trebuie s fie clare. Comentariile se folosesc pentru a adnota i explica codul. Acestea nu trebuie sa fie ambigue, ci din contra, ct mai specifice. Dac o persoan citete comentariile i rmne s se ntrebe ce nseamn, atunci acestea au sczut calitatea programului i au afectat nelegerea codului. Comentariile ajut la citirea codului. Comentariile sunt de obicei scrise deasupra codului pe care-l descriu, nu dedesubt. n acest fel, codul surs se citete n jos, aproape ca o carte. Comentariile ajut la pregtirea cititorului pentru ceea ce urmeaz s vin. Folosite cu spaii verticale, comentariile ajut la mprirea codului n paragrafe. Un comentariu introduce cteva linii, explicnd ce se intenioneaz s se obin, Urmeaz imediat codul, apoi o linie goal, apoi urmtorul bloc. Exist o convenie: un comentariu cu o linie goal naintea lui apare ca un nceput de paragraf, n timp ce un comentariu intercalat ntre dou linii de cod apare mai mult ca o propoziie n paranteze sau o not de subsol. Comentariile din antetul fiierului. Fiecare fiier surs ar trebui s nceap cu un bloc de comentarii ce descrie coninutul su. Acesta este doar o scurt prezentare, o prefa, furniznd cteva informaii eseniale ce se doresc ntotdeauna afiate de ndat ce este deschis un fiier. Dac exist acest antet, atunci un programator care deschide fiierul va avea ncredere n coninut; arat c fiierul a fost creat aa cum trebuie. Funcionalitatea fiecrui fiier surs trebuie comentat. Unele persoane susin c antetul ar trebui s furnizeze o list cu toate funciile, clasele, variabilele globale i aa mai departe, care sunt definite n fiier. Acesta este un dezastru pentru ntreinere; un astfel de comentariu devine rapid nvechit. Antetul fiierului trebuie s conin informaii despre scopul fiierului (de exemplu implementarea interfeei IDocument) i o declaraie cu drepturile de autor care s descrie proprietarul i regulile de copiere. Antet-ul nu trebuie s conin informaii care ar putea deveni uor nvechite, precum data cnd a fost ultima oar modificat fiierul. Probabil c data nu ar fi actualizat des i ar induce n eroare. De asemenea, nu trebuie s conin un istoric al fiierului surs care s descrie toate modificrile fcute. Dac trebuie s derulezi peste 10 pagini din istoricul modificrilor pentru a ajunge la prima linie de cod, atunci devine incomod lucrul cu fiierul. Din acest motiv, unii programatori pun o astfel de list la sfritul
94
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 4. Documentarea unui proiect. Fiiere de ajutor

fiierului. Chiar i aa, acesta poate deveni foarte mare i se va ncrca mai ncet. Degradarea comentariilor. Orice cod nentreinut corect tinde s se degradeze, pierznd din calitatea proiectrii iniiale. Totui, comentariile tind s se degradeze mult mai repede dect oricare alt parte de cod. Ele i pot pierde sincronizarea cu codul pe care l descriu i pot deveni profund suprtoare. Comentariile incorecte sunt mai duntoare dect lipsa comentariilor: dezinformeaz i induc n eroare cititorul. Cea mai simpl soluie este aceasta: cnd se repar, adaug sau modific codul, se repar, adaug sau modific orice comentarii din jurul su. Nu se modific cteva linii i att. Trebuie s ne asigurm c orice modificare din cod nu le va transforma n comentarii neadevrate. Corolarul este urmtorul: trebuie s crem comentarii uor de actualizat, dac nu, ele nu vor fi actualizate. Comentariile trebuie s fie clar legate de seciunea lor de cod i nu trebuie plasate n locaii obscure.

6. Lucrul cu fiiere n C#: ncrcare, salvare


Clasele OpenFileDialog i SaveFileDialog afieaz dialoguri de ncrcare/salvare a fiierelor. Aceste obiecte trebuie apelate din alte componente, de exemplu, la apsarea unui buton sau la alegerea unei opiuni dintr-un meniu, va aprea ferestra de dialog. n funcia apelant va trebui introdus un bloc de tipul:
if (openFileDialog.ShowDialog() != DialogResult.OK) // nu s-a apsat OK return;

Metoda de mai sus determin afiarea dialogului. Dac aceasta se execut corect (utilizatorul a ales un fiier), este disponibil proprietatea open/saveFileDialog.FileName, care conine numele fiierului dorit (cale complet i nume). Cteva proprieti: open/saveFileDialog.DefaultExt extensia ataat n mod automat fiierului; open/saveFileDialog.Filter dialogul de selecie de fiiere include un combo-box cu tipurile fiierelor. Cnd utilizatorul alege un tip de fiier din list, numai fiierele de tipul selectat sunt afiate n dialog.
95
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

Filter poate fi setat n Properties sau n codul surs, n formatul: "Text Files (*.txt)|*.txt|All Files (*.*)|*.*"; open/saveFileDialog.InitialDir directorul implicit unde se deschide dialogul. Poate fi de exemplu MyDocuments, dac aceast proprietate nu este specificat. Pentru directorul n care se afl programul, se folosete . .

n continuare, se vor defini nite stream-uri pentru fiiere. De exemplu:


StreamWriter sw = new StreamWriter(saveFileDialog.FileName); // operaii cu sw // de exemplu scriem n fiier un numr n cu 3 zecimale sw.WriteLine("Numarul este {0:F3}", n); sw.Close();

Pentru lucrul cu fiiere trebuie inclus namespace-ul System.IO.

7. Aplicaii
7.1. Realizai o interfa grafic pentru desenarea unui ptrat magic (figura 4.13), cu ajutorul clasei MagicBuilder, prezentat n continuare.

Figura 4.13. Exemplu de rezolvare

96
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 4. Documentarea unui proiect. Fiiere de ajutor


/************************************************************************** * * * File: MagicBuilder.cs * * Copyright: (c) 2003, A. Riazi * * Website: http://www.codeproject.com/KB/recipes/Magic_Square.asp * * Description: Calculates magic squares of any size. * * Translated into C# and adapted by Florin Leon * * http://florinleon.byethost24.com/lab_ip.htm * * * * This code and information is provided "as is" without warranty of * * any kind, either expressed or implied, including but not limited * * to the implied warranties of merchantability or fitness for a * * particular purpose. You are free to use this source code in your * * applications as long as the original copyright notice is included. * * * **************************************************************************/

using System; using System.Collections.Generic; namespace MagicSquare { public class MagicBuilder { private int[,] _matrix; private int _size; public MagicBuilder(int size) { _size = size; _matrix = new int[size, size]; } public int[,] BuildMagicSquare() { if (_size < 1 || _matrix == null) throw new Exception("Dimensiune incorecta"); MagicSquare(_matrix, _size); return _matrix; } private void MagicSquare(int[,] matrix, int n) { if (n % 2 == 1) OddMagicSquare(matrix, n); else { if (n % 4 == 0) DoublyEvenMagicSquare(matrix, n); 97
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C# else SinglyEvenMagicSquare(matrix, n); } } private void OddMagicSquare(int[,] matrix, int n) { int nsqr = n * n; int i = 0, j = n / 2; for (int k = 1; k <= nsqr; ++k) { matrix[i, j] = k; i--; j++; if (k % n == 0) { i += 2; --j; } else { if (j == n) j -= n; else if (i < 0) i += n; } } } private void DoublyEvenMagicSquare(int[,] matrix, int n) { int[,] mat1 = new int[n, n]; int[,] mat2 = new int[n, n]; int i, j; int index = 1; for (i = 0; i < n; i++) for (j = 0; j < n; j++) { mat1[i, j] = ((i + 1) % 4) / 2; mat2[j, i] = ((i + 1) % 4) / 2; matrix[i, j] = index; 98
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 4. Documentarea unui proiect. Fiiere de ajutor index++; } for (i = 0; i < n; i++) for (j = 0; j < n; j++) { if (mat1[i, j] == mat2[i, j]) matrix[i, j] = n * n + 1 - matrix[i, j]; } } private void SinglyEvenMagicSquare(int[,] matrix, int n) { int p = n / 2; int[,] mat = new int[p, p]; MagicSquare(mat, p); int i, j, k; for (i = 0; i < p; i++) for (j = 0; j < p; j++) { matrix[i, j] = mat[i, j]; matrix[i + p, j] = mat[i, j] + 3 * p * p; matrix[i, j + p] = mat[i, j] + 2 * p * p; matrix[i + p, j + p] = mat[i, j] + p * p; } if (n == 2) return; int[] mat1 = new int[p]; List<int> vect = new List<int>(); for (i = 0; i < p; i++) mat1[i] = i + 1; k = (n - 2) / 4; for (i = 1; i <= k; i++) vect.Add(i); for (i = n - k + 2; i <= n; i++) vect.Add(i);

99
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C# int temp; for (i = 1; i <= p; i++) for (j = 1; j <= vect.Count; j++) { temp = matrix[i - 1, vect[j - 1] - 1]; matrix[i - 1, vect[j - 1] - 1] = matrix[i + p - 1, vect[j - 1] - 1]; matrix[i + p - 1, vect[j - 1] - 1] = temp; } i = k; j = 0; temp = matrix[i, j]; matrix[i, j] = matrix[i + p, j]; matrix[i + p, j] = temp; j = i; temp = matrix[i + p, j]; matrix[i + p, j] = matrix[i, j]; matrix[i, j] = temp; } } }

Indicaii: Un ptrat magic este o matrice ptratic de dimensiune , care conine numerele ntregi din intervalul i n care suma elementelor pe linii, coloane i diagonale este aceeai. Pentru salvarea graficului, trebuie s se foloseasc un obiect de tip Bitmap, care dispune de funcii de salvare/ncrcare a imaginilor. Deoarece obiectul Bitmap va fi folosit att pentru desenarea ntr-un PictureBox ct i pentru salvarea imaginii ntr-un eveniment de apsare a unui buton, va trebui s avem un cmp n clas, instaniat n constructorul ferestrei:
private Bitmap _bmp; public void MainForm() { InitializeComponent(); // n constructorul ferestrei, dup metoda InitializeComponent(); _bmp = new Bitmap(pictureBox.Width, pictureBox.Height); }

Desenarea n Bitmap trebuie pus n legtur cu suprafaa de desenare a ferestrei din PictureBox. Atunci, n evenimentul Paint al acesteia, vom avea o secven de cod de forma:

100
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 4. Documentarea unui proiect. Fiiere de ajutor Graphics g = Graphics.FromImage(_bmp); // n continuare, desenarea se va face n g (n Bitmap) g.Clear(Color.White); ... // la sfrit, vom desena coninutul bitmap-ului n picture-box e.Graphics.DrawImage(_bmp, 0, 0);

buton:

Salvarea imaginii din Bitmap se va face n evenimentul Click al unui

_bmp.Save(saveFileDialog.FileName, System.Drawing.Imaging.ImageFormat.Png);

Cu linia de cod de mai sus, imaginea va fi salvat n format png. 7.2. Creai un fiier HLP sau un fiier CHM pentru programul Ptratul magic. Indicaie: Cu ajutorul componentei HelpProvider se poate afia un help bazat pe context, de exemplu pentru text-box-urile corespunztoare dimensiunii ptratului i sumei caracteristice. 7.3. Creai o documentaie API pentru clasa MagicBuilder folosind programul NDoc. Comentariile triple trebuie introduse cu o linie mai sus de prima linie a clasei, cmpului sau metodei comentate. Exemple:
/// <summary> /// Clasa pentru construirea unui ptrat magic /// </summary> public class MagicBuilder ... /// <summary> /// Constructorul clasei pentru ptratul magic /// </summary> /// <param name="size">Dimensiunea ptratului</param> public MagicBuilder(int size) ... 101
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C# /// <summary> /// Metoda care returneaz ptratul construit /// </summary> /// <returns>Matricea corespunztoare ptratului magic</returns> public int[,] BuildMagicSquare() ...

7.4. Opional. Realizai un program de generare a unui antet cu informaii pentru un fiier de cod surs C# (figurile 4.14 i 4.15).

Figura 4.14. Program generator de antete

102
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 4. Documentarea unui proiect. Fiiere de ajutor

Figura 4.15. Antet generat pentru un fiier surs

103
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

104
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 5

Diagrame UML
1. Obiective 2. Diagrame principale ale UML 3. Altova UModel 4. Aplicaii

1. Obiective
Limbajul Unificat de Modelare (engl. Unified Modeling Language, UML) este un limbaj pentru specificarea, vizualizarea, construirea i documentarea elementelor sistemelor software. Este un standard de facto pentru modelarea software. Obiectivele capitolului 5 sunt urmtoarele: 1. Prezentarea celor mai importante tipuri de diagrame UML 2.0; 2. Introducerea programului Altova UModel pentru desenarea diagramelor UML: a. Utilizarea diagramei de clase pentru generarea automat de cod C#; b. Generarea automat a diagramei de clase pe baza codului surs C#; c. Desenarea unor diagrame de cazuri de utilizare, clase, activiti i secvene.

2. Diagrame principale ale UML


2.1. Diagrama cazurilor de utilizare
O diagram de nivel nalt util n multe situaii este diagrama cazurilor de utilizare, care descrie mulimea de interaciuni dintre utilizator i sistem. Prin construirea unei colecii de cazuri de utilizare, putem descrie ntregul sistem ntr-o manier clar i concis. Cazurile de utilizare sunt denumite de obicei printr-o combinaie verb-substantiv, de exemplu:

105
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

Pltete factura, Creeaz cont etc. Notaia pentru un caz de utilizare este prezentat n figura 5.1.

Figura 5.1. Caz de utilizare

Un caz de utilizare trebuie s aib un iniiator al aciunii, numit actor. n cazul unui sistem bancar, retragerea banilor este fcut de clieni, astfel nct clientul devine unul din actori (figura 5.2).

Figura 5.2. Caz de utilizare cu actor

Actorii nu sunt numai oameni, ci orice cauz extern care iniiaz un caz de utilizare, de exemplu un alt sistem de calcul sau un concept mai abstract, precum timpul, de exemplu n ultima zi a lunii se actualizeaz statele de salarii. Pentru majoritatea sistemelor, un anumit actor poate interaciona cu mai multe cazuri de utilizare, iar un anumit caz de utilizare poate fi iniiat de actori diferii (figura 5.3).

Figura 5.3. Cazuri de utilizare cu actori multipli


106
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 5. Diagrame UML

2.2. Diagrama de clase


Modelarea conceptual (numit i modelarea domeniului) este activitatea de identificare a conceptelor importante pentru sistem. n cazul proiectrii orientate obiect, modelarea conceptual se realizeaz prin diagrama claselor, ntruct clasele reprezint concepte. Diagrama claselor furnizeaz structura codului care urmeaz s fie scris. Problema principal este identificarea conceptelor. Regula de urmat aici este: dac clientul nu nelege conceptul, probabil c nu este un concept. O clas se reprezint printr-o csu mprit n trei (figura 5.4). n partea de sus este notat numele clasei, n partea median sunt incluse atributele (cmpurile) iar n partea de jos operaiile (metodele) sale.

Figura 5.4. O clas n notaia UML

n figura 5.5 sunt prezentate notaiile pentru vizibilitatea atributelor i operaiilor (private, protejate, publice).

Figura 5.5. Vizibilitatea atributelor i operaiilor

2.2.1. Dependena Relaia de dependen apare cnd o clas folosete pentru scurt timp o alt clas, de exemplu trimiterea unui mesaj (apelarea din clasa A a unei metode din clasa B) sau trimiterea ca parametru ntr-o metod a clasei A a
107
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

unui obiect de tip B. n C#, un exemplu este clasa Math, ale crei metode statice sunt apelate punctual de obiectele altor clase. Se noteaz cu linie punctat cu o sgeat (figura 5.6).

Figura 5.6. Relaia de dependen

2.2.2. Asocierea Linia simpl n UML are rolul de asociere: o clas A are un cmp instaniat din cealalt clas B. Numerele descriu cardinalitatea asocierii, adic ne spun cte instane sunt permise din fiecare clas. Figura 5.7 prezint cteva cardinaliti posibile, dei din punct de vedere al notaiei nu exist restricii asupra cardinalitilor care pot fi specificate.

Figura 5.7. Cardinaliti

O greeal pe care o putem face n faza de analiz este s trasm o linie ntre dou clase, dar s nu notm numele asocierii. Dup ce vom trasa toate liniile, nu vom mai ti ce nseamn fiecare.

108
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 5. Diagrame UML

n figura 5.8 este prezentat un exemplu de asociere ntre clase, corespunztor fazei de analiz.

Figura 5.8. Asociere mai complex

Asocierile de mai sus sunt bidirecionale. ntr-o asociere unidirecional, cele dou clase sunt nrudite, dar numai o clas tie c exist relaia respectiv. n situaia din figura 5.9, managerul tie despre adres, dar adresa nu tie despre manager.

Figura 5.9. Asociere unidirecional

109
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

2.2.3. Agregarea i compunerea n cazul agregrii, un obiect este construit din altele. De exemplu, un calculator este o agregare ntre procesor, plac video, plac de sunet etc. (figura 5.10).

Figura 5.10. Relaia de agregare

Compunerea este un concept similar cu agregarea, ns mai puternic, deoarece implic faptul c ntregul nu poate exista fr pri. n exemplul de agregare de mai sus, dac se nltur placa de sunet, calculatorul rmne calculator. ns o carte nu poate exista fr pagini; o carte este compus din pagini. Notaia este asemntoare, dar rombul este plin (figura 5.11).

Figura 5.11. Relaia de compunere

2.2.4. Motenirea De multe ori, mai multe clase au atribute i operaii comune. Acestea pot fi introduse ntr-o singur clas i motenite n celelalte, de exemplu clasele din figura 5.12. Dac am mai vrea s adugm o clas Pisic, ar trebui s repetm atributele i operaiile comune. Soluia este motenirea dintr-o clas mai general.
110
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 5. Diagrame UML

Figura 5.12. Clase cu potenial de generalizare

Notaia UML pentru motenire (generalizare) este cea din figura 5.13.

Figura 5.13. Relaia de motenire

Trebuie s subliniem faptul c atributul vrst a fost transformat din privat n protejat, pentru a putea fi accesat n clasele derivate.

111
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

2.2.5. Metode abstracte i virtuale Clasele derivate pot redefini implementarea unor metode. n exemplul urmtor, clasele Lup, Pete i AltAnimal sunt derivate din clasa Animal, ns primele dou reimplementeaz metoda Mnnc n modul lor specific. Notaia n acest caz este cea din figura 5.14.

Figura 5.14. Notaia pentru metode virtuale

Cuvintele introduse ntre << i >> se numesc stereotipuri. De multe ori avem nevoie s lsm o metod neimplementat ntr-o clas (metod abstract) i s o implementm pe un nivel mai de jos al ierarhiei. Clasele i metodele abstracte se noteaz cu italice (figura 5.15).

Figura 5.15. Notaia pentru clase i metode abstracte

112
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 5. Diagrame UML

2.2.6. Interfee S presupunem c InstrumentMuzical din exemplul precedent e acum o interfa iar clasele Pian i Vioar trebuie s implementeze metoda Cnt. Notaia este asemntoare celei de la motenirea de clase, dar cu linie punctat, iar interfaa poate fi declarat explicit cu un stereotip (figura 5.16).

Figura 5.16. Notaia pentru interfee

2.2.7. Trsturi statice n notaia UML, trsturile (atributele/cmpurile operaiile/metodele) statice se subliniaz, ca n figura 5.17. i

Figura 5.17. Notaia pentru trsturi statice

113
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

2.3. Diagrame de activiti


Diagramele de activiti sunt folosite pentru modelarea proceselor sau a algoritmilor din spatele unui anumit caz de utilizare. Notaia este urmtoarea: nod iniial: un cerc plin; este punctul de start al diagramei; nod final: un cerc plin nconjurat de un alt cerc; o diagram poate avea 0, 1 sau mai multe noduri finale; aciuni: dreptunghiurile rotunjite reprezint paii activi executai n cadrul procesului; arce: sgeile diagramei; punct final al fluxului: un cerc cu un X n interior; indic faptul c procesul se oprete n acest punct; ramificaie (engl. fork): o bar neagr cu un flux de intrare i mai multe fluxuri de ieire; denot nceputul unor activiti desfurate n paralel; reunire (engl. join): o bar neagr cu mai multe fluxuri de intrare i un flux de ieire; denot sfritul prelucrrilor paralele; condiie: text asociat unui flux care definete o propoziie cu o valoare de adevr i care trebuie s fie adevrat pentru continuarea execuiei; decizie: un romb cu un flux de intrare i mai multe fluxuri de ieire; fluxurile de ieire includ condiii; mbinare (engl. merge): un romb cu mai multe fluxuri de intrare i un flux de ieire; toate fluxurile de intrare trebuie s ating acest punct pentru ca procesul s continue; partiie sau culoar (engl. partition / swimlane): o parte a diagramei care indic cine ndeplinete aciunile; not: un comentariu care poate aduce informaii suplimentare privind scopul, utilizarea sau constrngerile unei entiti.

n figura 5.18 este prezentat o diagram de activiti cu decizii. Candidatul trebuie s fie admis este o not asociat unei decizii.

114
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 5. Diagrame UML

Figura 5.18. Diagram de activiti cu decizii

n figura 5.19 este prezentat o alt diagram de activiti, cu partiii i ramificaii.

115
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

Figura 5.19. Diagram de activiti cu partiii i ramificaii


116
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 5. Diagrame UML

2.4. Diagrama de secvene


Diagrama de secvene pune accentul pe aspectul temporal (ordonarea mesajelor). Notaia grafic este un tabel care are pe axa X obiecte, iar pe axa Y mesaje ordonate cresctor n timp. Axa Y arat pentru fiecare obiect timpul ca o linie vertical punctat, numit linia vieii unui obiect (engl. lifeline) i perioada n care obiectul deine controlul execuiei (reprezentat printr-un dreptunghi) i efectueaz o aciune, direct sau prin intermediul procedurilor subordonate. n figura 5.20 este descris interaciunea dintre doi abonai ai unei reele de telefonie. De remarcat c n diagrama de secvene utilizm obiecte, nu clase. ntr-un program pot exista mai multe instane ale aceleiai clase care au roluri diferite n sistem. Un obiect este identificat de numele su i numele clasei pe care o instaniaz. Numele obiectului poate s lipseasc dac nu este semnificativ pentru nelegerea comportamentului sistemului. Liniile orizontale continue semnific mesaje iniiate de obiecte, iar liniile orizontale punctate reprezint mesaje-rspuns.

Figura 5.20. Diagram de secvene

117
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

3. Altova UModel
Altova UModel este un instrument vizual pentru crearea de diagrame UML. Poate genera cod Java, C# i Visual Basic .NET pe baza diagramelor i poate s realizeze diagrame UML ale programelor existente. Este posibil de asemenea ajustarea codului existent prin modificarea diagramelor corespunztoare. Fiecare tip de diagram are o bar de instrumente corespunztoare cu elementele UML caracteristice, care pot fi introduse n fereastra de desenare, conectate i modificate (figura 5.21).

Figura 5.21. Diagramele UML n Altova UModel

118
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 5. Diagrame UML

3.1. Diagrama de clase


Proprietile (cmpurile) i operaiile (metodele) unei clase pot fi adugate mai rapid cu ajutorul tastelor F7, respectiv F8. Din bara de instrumente sau din conectorii dreptunghiului asociat clasei se creeaz tipurile de legturi dintre clase, de exemplu asociere, motenire etc. Membrii unei clase pot fi redenumii direct pe diagram sau din fereastra Model Tree. Implicit, diagramele au vizibilitatea marcat grafic iar clasele au prima csu colorat cu un gradient. Aspectul vizual al diagramelor poate fi configurat folosind stilurile: View Styles. De exemplu, diagrama din figura 5.22 sus este echivalent cu cea de jos, eliminnd gradientul i marcnd proprietatea Show Visibility drept UML Style n loc de UModel Style. Alte proprieti utile sunt: Show Namespace, Show Stereotypes.

Figura 5.22. Diagrame de clase cu diferite stiluri

119
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

3.1.1. Generarea de cod Pentru a genera cod (C#) pe baza unei diagrame de clase, trebuie mai nti creat un pachet care va conine clasele. n Model Tree, click dreapta pe Root, New Element Package. Pe acest pachet trebuie aplicat profilul limbajului dorit pentru generare: click dreapta pe pachetul creat, Code Engineering Set as C# Namespace Root. n pachet se introduce apoi o diagram de clase i se adaug clasele. Tipurile proprietilor se pot completa din lista de tipuri din modelul ales, la apsarea : dup numele proprietii (figura 5.23).

Figura 5.23. Tipurile proprietilor

Analog, pentru operaii se vor aduga parametrii i tipul de return (figura 5.24). Numele parametrilor sunt precedate de cuvintele cheie in (parametru normal), out (parametru out), inout (parametru ref).

Figura 5.24. Parametrii i tipul de return pentru operaii


120
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 5. Diagrame UML

Pentru o clas se pot aduga automat accesori prin click dreapta, Create getter/setter Operations... (figura 5.25).

Figura 5.25. Adugarea de accesori

Caracteristicile specifice ale unei operaii se pot introduce din fereastra Properties, de exemplu cu stereotipurile <<constructor>>, <<virtual>>, <<abstract>>, <<override>> etc. (figura 5.26).

Figura 5.26. Adugarea de stereotipuri

121
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

Trebuie precizat faptul c aceste stereotipuri devin disponibile doar dup crearea unui pachet setat ca C# Namespace Root, n care au fost adugate clasele. Vizibilitatea membrilor se poate seta de asemenea apsnd pe imaginea din stnga numelui sau din fereastra Properties. Se finalizeaz diagrama de clase (figura 5.27), care se poate exporta i ca imagine din File Save Diagram As Image...

Figura 5.27. Diagram de clase cu asociere i motenire

Figura 5.28. Adugarea unui component


122
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 5. Diagrame UML

Pentru generarea efectiv a codului, mai trebuie adugat un component n proiect, deoarece numai un astfel de element conine n viziunea UML codul propriu-zis pentru implementare: click dreapta pe Root, New Element Component. Dup crearea componentului, se trag (drag and drop) clasele din diagrama de clase n component. Automat se creeaz nite relaii de realizare (figura 5.28). Pentru component mai trebuie specificate n fereastra Properties limbajul de programare dorit i calea ctre directorul unde se vor genera fiierele surs (figura 5.29).

Figura 5.29. Proprietile componentului

Apoi se face click dreapta pe numele componentului (aici MyComponent), Code Engineering Override Program Code from UModel Component... (figura 5.30).

Figura 5.30. Setrile pentru sincronizare

123
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

Scheletul de program generat pentru exemplul de mai sus este urmtorul:


public class ClassA { protected int _propInt; public virtual void OperationA1(int a, out int b, ref int c) { } public int OperationA2() { } } public class ClassB : ClassA { private int _propertyB1; private ClassC _propertyB2; public bool OperationB1() { } } public class ClassC { private double _propertyC; public int OperationC() { } public double PropertyC { set { } get { } } }

124
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 5. Diagrame UML

3.1.2. Crearea diagramei unui proiect existent Importarea de cod pentru crearea diagramei de clase este destul de simpl (figura 5.31); se alege Project Import Source Directory... pentru a prelua fiierele surs din directorul specificat (posibil recursiv) sau Project Import Source Project... pentru importarea unei soluii Visual Studio (fiierul sln).

Figura 5.31. Setrile pentru generarea unei diagrame din cod

Dac se import codul generat anterior, se observ c UModel afieaz automat relaiile de generalizare (motenire) dar nu i pe cele de asociere (sau agregare/compunere). Acestea pot fi indicate n diagram prin click dreapta pe un cmp i alegerea opiunii de afiare ca asociere (figura 5.32). Relaiile de dependen nu apar automat, ns ntr-o diagram nu trebuie s existe clase izolate. Ar nsemna c acestea nu sunt utilizate deloc i atunci nu se justific prezena lor.

125
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

Figura 5.32. Afiarea unei proprieti ca asociere

S considerm urmtorul program:


namespace Dependency { public class A { public static int Add(int a, int b) { return a + b; } } public class B { private int _x, _y; private int _sum;

126
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 5. Diagrame UML public int Sum { get { return _sum; } } public B(int x, int y) { _x = x; _y = y; _sum = A.Add(_x, _y); } } class Program { static void Main(string[] args) { B b = new B(1, 2); Console.WriteLine(b.Sum); } } }

La importarea sa, diagrama UModel este cea din figura 5.33.

Figura 5.33. Clasele importate

n acest caz, relaiile de dependen ntre Program i B, respectiv ntre B i A trebuie trasate manual (figura 5.34).

Figura 5.34. Adugarea relaiilor de dependen


127
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

3.1.3. Aranjarea automat a elementelor din diagrame O funcionalitate foarte util este dispunerea automat a elementelor n fereastr (click dreapta n fereastr, Autolayout All Force Directed sau Hierarchical).

3.2. Celelalte diagrame


Prin click dreapta pe Root, New Diagram pot fi introduse n proiect orice diagrame UML, iar n bara de meniuri apar elementele UML specifice tipului respectiv de diagram.

4. Aplicaii
4.1. Generai fiiere de cod C# dintr-o diagram de clase (se poate urmri exemplul prezentat mai sus). 4.2. Realizai diagrama de clase a unui proiect C# prin importare. 4.3. Desenai diagramele din figurile: 5.3, 5.6, 5.8, 5.10, 5.11, 5.15, 5.16, 5.17, 5.18, 5.19 i 5.20. Indicaie: Notaiile pot fi particularizate prin modificarea proprietilor elementelor, de exemplu modificarea tipului implicit de asociere (figura 5.35).

Figura 5.35. Modificarea tipului de asociere


128
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 5. Diagrame UML

4.4. Tem pentru acas. Desenai diagrama de activiti i diagrama de secvene pentru un proiect C# la alegere. Diagrama de secvene trebuie realizat manual la un nivel mai nalt, nu diagrama realizat automat de versiunile recente ale UModel, n care reprezentarea este la nivel de linie de cod. Diagramele astfel rezultate sunt prea complexe pentru a fi nelese. Diagramele trebuie exportate i n format imagine, de preferin png.

129
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

130
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 6

Arhitectura MVC
1. Obiective 2. Introducere. Arhitectura cu trei straturi 3. Arhitectura MVC 4. Arhitectura MVP 5. Aplicaii

1. Obiective
Obiectivul principal al acestui capitol este implementarea unui program dup ablonul arhitectural Model-Vizualizare-Prezentator (engl. Model-View-Presenter, MVP), o variant a arhitecturii clasice ModelVizualizare-Controlor (engl. Model-View-Controller, MVC). Ca obiective detaliate, vom avea: 1. Obiective de proiectare: particularizarea arhitecturii MVP pentru o aplicaie cu interfa de tip consol, subliniind faptul c arhitectura este independent de tipul interfeei cu utilizatorul; 2. Obiective de programare: realizarea unui meniu consol structurat pe niveluri; 3. Obiective diverse: calcularea distanei ntre dou puncte de pe suprafaa Pmntului definite de coordonatele lor geografice.

2. Introducere. Arhitectura cu trei straturi


Una din recomandrile de baz ale ingineriei programrii este structurarea arhitecturii unei soluii pe niveluri, adic mprirea sistemului n mai multe componente ordonate ierarhic, fiecare cu limitri legate de modul de interaciune. Din punct de vedere al terminologiei, se folosete strat (engl. tier) pentru a indica o separare fizic a componentelor, adic assembly-uri (dll, exe) diferite pe aceeai main sau pe maini diferite. Termenul de nivel (engl. layer) indic o separare logic a componentelor, de exemplu namespace-uri diferite.
131
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

O abordare simpl i des ntlnit este utilizarea unei arhitecturi cu dou straturi (engl. two-tier architecture). n acest caz, aplicaia separ stratul de prezentare de stratul datelor aplicaiei. Datele reprezint entitile care definesc problema i de obicei corespund unor tabele n baze de date. Clasele de prezentare au responsabiliti precum recepionarea intrrilor de la utilizator (texte introduse, apsarea unor butoane, alegerea unor opiuni din meniuri etc.), apelurile ctre stratul de date, deciziile privind informaiile care vor fi artate utilizatorului i afiarea ieirilor (texte, grafice etc.). Aceste responsabiliti sunt destul de numeroase i, pe msur ce sistemul evolueaz, stratul de prezentare poate deveni suprancrcat. O soluie natural este divizarea acestui strat prea extins n dou alte straturi: de prezentare, pentru preluarea intrrilor i afiarea ieirilor, i respectiv de logic a aplicaiei, pentru asigurarea comunicaiilor cu stratul de acces la date i pentru luarea deciziilor de control. Stratul de logic include toate prelucrrile efective care manipuleaz datele interne i pe cele ale utilizatorului, cu ajutorul algoritmilor specifici, pentru a controla fluxul aplicaiei. Figura 6.1 prezint comparativ arhitecturile cu dou i trei straturi.

Figura 6.1. Arhitectura cu dou straturi (stnga). Arhitectura cu trei straturi (dreapta)

132
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 6. Arhitectura MVC

3. Arhitectura MVC
Arhitectura cu dou straturi, n care se consider c schimbul de informaii are loc ntre interfaa cu utilizatorul i bazele de date (sau n general orice modalitate de stocare a datelor, inclusiv fiiere text, xml etc.) presupune ca din interfa s se acceseze i s se modifice direct datele. Totui, aceast abordare are cteva probleme semnificative. n primul rnd, interfaa cu utilizatorul se schimb de obicei mai des dect baza de date. n al doilea rnd, majoritatea aplicaiilor conin cod funcional (logica) ce realizeaz prelucrri mult mai complexe dect simpla transmitere de date. ablonul arhitectural Model-Vizualizare-Controlor izoleaz interfaa, codul funcional i datele, astfel nct modificarea unuia din aceste trei componente s nu le afecteze pe celelalte dou. O aplicaie bazat pe ablonul MVC va avea trei module corespunztoare: 1. Model: conine datele, starea i logica aplicaiei. Dei nu cunoate Controlorul i Vizualizarea, furnizeaz o interfa pentru manipularea i preluarea strii i poate trimite notificri cu privire la schimbarea strii. De obicei primete cereri privind starea datelor de la Vizualizare i instruciuni de modificare a datelor sau strii de la Controlor; 2. Vizualizare: afieaz Modelul ntr-o form potrivit pentru utilizator. Pentru un sigur Model pot exista mai multe Vizualizri, de exemplu o list de elemente poate fi afiat ntr-un control vizual precum ListBox, ntr-o consol sau ntr-o pagin web; 3. Controlor: primete intrrile de la utilizator i apeleaz obiectele Modelului pentru a prelucra noile informaii. Exist mai multe variante ale arhitecturii MVC, ns n general fluxul de control este urmtorul: 1. Utilizatorul interacioneaz cu interfaa aplicaiei, iar Controlorul preia intrarea i o interpreteaz ca pe o aciune ce poate fi recunoscut de ctre Model; 2. Controlorul trimite Modelului aciunea utilizatorului, ceea ce poate conduce la schimbarea strii Modelului; 3. n vederea afirii rezultatului de ctre Vizualizare, Controlorul i poate trimite acesteia o cerere de actualizare, sau Modelul i trimite o notificare privind schimbarea strii sale;
133
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

4. Vizualizarea preia datele necesare din Model i le afieaz. n continuare, aplicaia ateapt o nou aciune a utilizatorului iar ciclul se reia. Trebuie precizat c Modelul nu este doar o baz de date, ci ncapsuleaz i logica domeniului necesar pentru manipularea datelor din aplicaie. De multe ori se folosete i un mecanism de stocare persistent a acestora, de exemplu ntr-o baz de date, ns arhitectura MVC nu menioneaz explicit stratul de acces la date; acesta se consider implicit ca parte din Model. Figura 6.2 prezint relaiile structurale ntre cele trei module.

Figura 6.2. Relaiile structurale ntre componentele arhitecturii MVC

Pentru o aplicaie mai simpl, aceste module pot reprezenta clase. Din punctul de vedere al implementrii, sgeile de asociere nseamn c: Vizualizarea va avea un cmp de tip Model; de obicei va primi ca parametru n constructor o referin la obiectul Model; Controlorul va avea dou cmpuri de tip Vizualizare i Model; de obicei va primi ca parametri n constructor referine la obiectele Vizualizare i Model.

Mai ales n aplicaiile web, este clar definit separaia dintre Vizualizare (browser-ul) i Controlor (componentele server care rspund cererilor http). Prin separarea celor trei funcionaliti se atinge o cuplare slab ntre module, caracteristic dorit n toate programele deoarece modificrile dintr-o seciune a codului nu necesit modificri i n alte seciuni. Decuplarea scade complexitatea proiectrii i crete flexibilitatea i potenialul de reutilizare.

134
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 6. Arhitectura MVC

Avantajele principale ale ablonului MVC sunt urmtoarele: Modificri rapide. Clasele ablonului trebuie doar s implementeze nite interfee prestabilite, astfel nct acestea s cunoasc metodele pe care le pot apela n celelalte clase. Cnd se doresc modificri, nu trebuie rescris o clas, se poate implementa una nou i se poate utiliza direct, chiar alturi de una veche. De asemenea, Vizualizrile i Modelele existente pot fi refolosite pentru alte aplicaii cu un Controlor diferit. Modele de date multiple. Modelul nu depinde de nicio alt clas din ablon. Datele pot fi stocate n orice format: text, xml sau baze de date Access, Oracle, SQL Server etc.; Interfee multiple. Deoarece Vizualizarea este separat de Model, pot exista n aplicaie mai multe tipuri de Vizualizri ale acelorai date. Utilizatorii pot alege mai multe scheme de afiare: mai multe skin-uri sau comunicarea n mai multe limbi. Aplicaia poate fi extins uor pentru a include moduri de vizualizare complet diferite: consol, interfa grafic cu utilizatorul n ferestre (desktop), documente web sau pentru PDA-uri.

4. Arhitectura MVP
n abordarea clasic, descris de Trygve Reenskaug pe cnd lucra la limbajul Smalltalk la Xerox PARC (1978-1979), logica este n Model, iar Controlorul gestioneaz intrrile de la utilizator. Pentru aplicaiile de tip consol, este relativ simplu ca intrrile s fie preluate de Controlor iar afiarea s se fac de ctre Vizualizare, pe baza datelor din Model. Pentru aplicaiile moderne, cu interfee grafice cu utilizatorul (GUI) precum ferestrele Windows, clasele de vizualizare sunt cele care primesc intrrile utilizatorului. De aceea, n astfel de situaii, Vizualizarea i Controlorul nu mai sunt clar delimitate. n Cocoa (unul din mediile de dezvoltare de aplicaii orientate obiect native ale Apple pentru Mac OS X) i DDay.MVC (proiectul DDay reprezint o colecie de biblioteci open-source pentru tehnologiile .NET), Controlorul conine logica aplicaiei. Pentru a rspunde noilor realiti ce privesc interaciunea utilizatorilor cu interfeele aplicaiilor, a fost propus ablonul ModelVizualizare-Prezentator, MVP. Aici, stratul de prezentare const n obiecte
135
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

de Vizualizare iar logica aplicaiei const n obiecte de control (Prezentator/Controlor). Pentru fiecare obiect de vizualizare exist un obiect de control. Din punct de vedere al terminologiei, se poate utiliza termenul de Controlor pentru Prezentator n ablonul MVP, deoarece acesta poate fi considerat o variant modern a ablonului clasic MVC. Dei ambele abloane, MVC i MVP, se bazeaz pe principiul comun al arhitecturii cu trei straturi, acestea au dou diferene majore: 1. n MVC, Controlorul primete i prelucreaz intrrile de la utilizator iar n MVP, Vizualizarea primete intrrile i apoi deleag prelucrrile ctre Controlorul corespunztor; 2. n MVC, Vizualizarea primete notificri privind schimbrile Modelului i afieaz noile informaii pentru utilizator. n MVP, Controlorul modific direct Vizualizarea, ceea ce face ablonul MVP mai uor de folosit dect ablonul MVC. Aceste diferene fac ablonul MVP mai atractiv dect ablonul MVC pentru aplicaiile din prezent.

4.1. Variante de actualizare a Vizualizrii


Cnd Modelul este actualizat, Vizualizarea trebuie de asemenea actualizat pentru a reflecta modificrile. Actualizarea Vizualizrii poate fi realizat n dou variante: Vizualizarea pasiv (engl. Passive View) i Controlorul supervizor (engl. Supervising Controller). Figura 6.3 ilustreaz modelele logice ale celor dou variante.

Figura 6.3. Vizualizarea pasiv (stnga) i Controlorul supervizor (dreapta)

n abordarea Vizualizrii pasive, Prezentatorul actualizeaz Vizualizarea pentru a reflecta schimbrile din Model. Interaciunea cu
136
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 6. Arhitectura MVC

Modelul este gestionat exclusiv de Prezentator iar Vizualizarea nu i poate da seama direct de schimbrile din Model. La rndul su, Vizualizarea este actualizat exclusiv de ctre Prezentator. Abordarea este util atunci cnd Prezentatorul trebuie s realizeze unele prelucrri complexe asupra datelor, nainte de a afia informaiile pentru utilizator. Acestea apar de exemplu atunci cnd strile controalelor din interfaa grafic depind de anumite prelucrri ale datelor. S considerm cazul n care un utilizator dorete s mprumute o carte a unui anumit autor de la bibliotec. Dac toate crile autorului respectiv sunt deja mprumutate, butonul mprumut poate fi dezactivat. n aceast situaie, faptul c mprumutul este imposibil nu este reinut n Model, ci este determinat de Prezentator, care apoi i cere Vizualizrii s dezactiveze butonul respectiv. n abordarea Controlorului supervizor, Vizualizarea interacioneaz direct cu Modelul pentru a transfera date, fr intervenia Prezentatorului. Prezentatorul actualizeaz Modelul i manipuleaz starea Vizualizrii doar n cazurile n care exist o logic complex a interfeei cu utilizatorul. Vizualizarea poate fi actualizat i direct, pe baza modificrilor datelor din Model. Astfel de transferuri simple, n care Vizualizarea comunic direct cu Modelul, sunt n general situaiile n care se schimb unele date n Model iar acestea sunt preluate i afiate n Vizualizare, fr prelucrri suplimentare. De exemplu, interfaa afieaz o list de cri mprumutate de un student de la bibliotec, list pstrat de Model ntr-o baz de date. Cnd studentul mprumut o nou carte, baza de date se schimb iar Vizualizarea preia direct din Model elementele listei pentru afiare. Vizualizarea pasiv este asemntoare arhitecturii cu trei straturi tipice, n care stratul de logic a aplicaiei se interpune ntre stratul de prezentare i stratul de acces la date. Decizia asupra alegerii uneia din cele dou variante depinde de prioritile aplicaiei. Dac este mai important testabilitatea, Vizualizarea pasiv este mai potrivit, deoarece se poate testa toat logica interfeei cu utilizatorul prin testarea Prezentatorului. Pe de alt parte, dac simplitatea este mai important, Controlorul supervizor este o opiune mai bun deoarece, pentru schimbri mici n interfa, nu mai trebuie inclus cod n Prezentator pentru actualizarea Vizualizrii. Astfel, Controlorul supervizor necesit de obicei mai puin cod ntruct Prezentatorul nu mai efectueaz actualizrile simple ale Vizualizrii. abloanele MVC i MVP au scopuri similare, ns difer prin modalitile n care i ating aceste scopuri.
137
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

5. Aplicaii
5.1. Realizai un program de tip consol cu arhitectura MVP, Controlor supervizor pentru determinarea costurilor unei firme de transport. Se vor putea calcula costurile de transport ntre dou orae, identificate prin nume, latitudine i longitudine. Aplicaia va permite dou roluri: administrator i utilizator, cu funcii diferite (figura 6.4).

Figura 6.4. Meniul principal

Pentru rolul de utilizator comenzile disponibile sunt prezentate n figura 6.5.

Figura 6.5. Meniul rolului de utilizator


138
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 6. Arhitectura MVC

Pentru rolul de administrator comenzile disponibile sunt prezentate n figura 6.6.

Figura 6.6. Meniul rolului de administrator

Indicaii: Se furnizeaz codul surs pentru Model, mpreun cu un fiier text care conine mai multe orae;

Model.cs
using System; using System.Collections.Generic; using System.IO; using System.Text; namespace TransportInfo { public class Model : IModel { #region Fields private const string CityFileName = "cities.txt"; private List<City> _cityList; private bool _wasModified; // lista cu orae va fi salvat n final doar dac s-a modificat #endregion

139
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C# #region Properties public int CityCount { get { return _cityList.Count; } } #endregion #region Constructor public Model() { _cityList = new List<City>(); _wasModified = false; } #endregion

#region Public Methods public int GetNumberOfCities() { return _cityList.Count; } public bool DataExists() { if (!File.Exists(CityFileName)) { _wasModified = true; return false; } else return true; } public void InitializeData() { StreamReader sr = new StreamReader(CityFileName); string line; while ((line = sr.ReadLine()) != null) _cityList.Add(ParseCityLine(line)); sr.Close(); }

140
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 6. Arhitectura MVC public bool Add(City city) { // dac un ora cu acelai nume exist deja, el va fi ters bool overwrite = false; for (int i = 0; i < _cityList.Count; i++) { if (_cityList[i].Name.Trim().ToUpper() == city.Name.Trim().ToUpper()) { _cityList.RemoveAt(i--); overwrite = true; } } // adugarea noului ora _cityList.Add(city); _wasModified = true; return !overwrite; } public bool Delete(string cityName) { for (int i = 0; i < _cityList.Count; i++) { if (_cityList[i].Name == cityName) { _cityList.RemoveAt(i); _wasModified = true; return true; } } return false; } public bool Exists(string cityName) { // dac un ora exist for (int i = 0; i < _cityList.Count; i++) { if (_cityList[i].Name == cityName) return true; } return false; } 141
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C# public City Search(string cityName) { // caut un ora dup nume i returneaz obiectul corespunztor for (int i = 0; i < _cityList.Count; i++) { if (_cityList[i].Name == cityName) return _cityList[i]; } return new City(); } public string ListAll() { // creeaz un string cu numele tuturor oraelor if (_cityList.Count == 0) return string.Empty; StringBuilder sb = new StringBuilder(); sb.Append(_cityList[0].Name); for (int i = 1; i < _cityList.Count; i++) { sb.Append(", "); sb.Append(_cityList[i].Name); } return sb.ToString(); } /// <summary> /// Salveaz datele doar dac lista de orae s-a modificat /// </summary> /// <returns>Returneaz true dac noile date au fost salvate </returns> public bool SaveData() { // dac datele s-au modificat, ele sunt salvate if (_wasModified) { StreamWriter sw = new StreamWriter(CityFileName); for (int i = 0; i < _cityList.Count; i++) { City c = _cityList[i]; sw.WriteLine(c.Name + "\t" + c.Latitude + "\t" + c.Longitude); } 142
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 6. Arhitectura MVC sw.Close(); return true; } else return false; } #endregion #region Private Methods private static City ParseCityLine(string line) { // citete informaiile unui ora de pe o linie din fiier string[] toks = line.Split('\t'); City city = new City(toks[0], Convert.ToDouble(toks[1]), Convert.ToDouble(toks[2])); return city; } #endregion } }

cities.txt
Iasi Bacau Piatra Neamt Suceava Botosani Vaslui Bucuresti Cluj-Napoca Timisoara Constanta Brasov Chisinau Balti Amsterdam Atena Belgrad Berlin Bruxelles Budapesta 47.167 46.567 46.933 47.667 47.733 46.633 44.44 46.78 45.76 44.18 45.66 47.033 47.75 52.383 37.967 44.817 52.533 50.85 47.483 27.583 26.917 26.383 26.183 26.667 27.733 26.1 23.59 21.23 28.63 25.61 28.833 27.917 4.9 23.767 20.45 13.4 4.35 19.083

143
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C# Londra Madrid Moscova Oslo Praga Paris Roma Sofia Viena 51.517 40.417 55.75 59.917 50.083 48.833 41.9 42.75 48.2 -0.1 -3.75 37.583 10.75 14.367 2.333 12.5 23.333 16.367

City.cs

Se furnizeaz codul surs pentru structura corespunztoare unui ora, mpreun cu funcia de calcul al distanei;

namespace TransportInfo { public struct City { // readonly pentru ca structura s fie immutable // alternativa este abordarea cu cmpuri private i proprieti publice public readonly double Latitude, Longitude; public readonly string Name; public City(string name, double latitude, double longitude) { Name = name; Latitude = latitude; Longitude = longitude; } } }

Calculator.cs
namespace TransportInfo { public class BusinessCalculator { #region Public Static Methods public static double Distance(City c1, City c2) { // calculeaz distana n kilometri ntre dou puncte de pe suprafaa Pmntului // identificate prin latitudine i longitudine utiliznd coordonate sferice double a1 = c1.Latitude * Math.PI / 180.0; 144
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 6. Arhitectura MVC double b1 = c1.Longitude * Math.PI / 180.0; double a2 = c2.Latitude * Math.PI / 180.0; double b2 = c2.Longitude * Math.PI / 180.0; const double EarthRadius = 6378; // raza Pmntului n km return (int)(EarthRadius * Math.Acos(Math.Cos(a1) * Math.Cos(b1) * Math.Cos(a2) * Math.Cos(b2) + Math.Cos(a1) * Math.Sin(b1) * Math.Cos(a2) * Math.Sin(b2) + Math.Sin(a1) * Math.Sin(a2))); } public static double Cost(double distance) { // aici se poate introduce orice funcie de calcul al costului double euro = 5 + distance / 30.0; return euro * 4.3; } #endregion } }

ntruct cele trei meniuri au structuri similare, se recomand crearea unei metode comune care s primeasc drept parametru lista de opiuni posibile; Se recomand ca opiunile alese de utilizator s fie tratate ca o enumeraie.

public enum UserChoice { AdminMenu, UserMenu, PreviousMenu, Route, AddCity, RemoveCity, Exit, List, Undefined }; public enum MenuState { Main, Administrator, User };

Metoda Main din clasa Program poate avea coninutul urmtor:


static class Program { static void Main() { Model model = new Model(); ConsoleView view = new ConsoleView(model); Presenter presenter = new Presenter(view, model); view.SetPresenter(presenter); view.Start(); } }

145
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

146
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Figura 6.7. Exemplu de rezolvare: diagrama de clase

Capitolul 6. Arhitectura MVC

Un exemplu de diagram de clase pentru aplicaie este prezentat n figura 6.7. Pentru creterea claritii, nu s-au mai reprezentat explicit relaiile de asociere pentru cmpurile de tip IPresenter, IModel, IView i nici numele metodelor din interfee implementate de clasele concrete. Metoda ListAll din clasele View apeleaz direct metoda ListAll din clasa Model. Aici apare diferena ntre abordarea Controlorului supervizor i cea a Vizualizrii pasive. Dac s-ar fi utilizat cea de a doua abordare, ListAll din View ar fi apelat o metod corespunztoare din Presenter, iar aceasta ar fi apelat metoda ListAll din Model. Proiectele soluiei i fiierele surs pot fi structurate ca n figura 6.8.

Figura 6.8. Exemplu de rezolvare: structurarea soluiei

5.2. Tem pentru acas. Pstrnd aceleai clase pentru Model i Prezentator, realizai o Vizualizare nou, cu o interfa grafic de tip Windows Forms, cu aceeai funcionalitate ca i aplicaia consol dezvoltat anterior. Indicaii: Metoda Main din clasa Program poate avea coninutul urmtor:

147
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C# static class Program { [STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Model model = new Model(); FormView view = new FormView(); Presenter presenter = new Presenter(view, model); view.SetModel(model); view.SetPresenter(presenter); Application.Run(view); } }

Pentru a fora utilizatorul s foloseasc doar opiunea de Ieire pentru a nchide programul, butonul de nchidere a ferestrei poate fi dezactivat cu ajutorul secvenei urmtoare de cod:
#region Disable Close X Button const int MF_BYPOSITION = 0x400; [DllImport("User32")] private static extern int RemoveMenu(IntPtr hMenu, int nPosition, int wFlags); [DllImport("User32")] private static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert); [DllImport("User32")] private static extern int GetMenuItemCount(IntPtr hWnd); private void FormView_Load(object sender, EventArgs e) { IntPtr hMenu = GetSystemMenu(this.Handle, false); int menuItemCount = GetMenuItemCount(hMenu); RemoveMenu(hMenu, menuItemCount - 1, MF_BYPOSITION); } #endregion

Un exemplu de interfa grafic este prezentat n capturile ecran din figurile 6.9, 6.10 i 6.11.

148
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 6. Arhitectura MVC

Figura 6.9. Exemplu de rezolvare: meniul principal

Figura 6.10. Exemplu de rezolvare: rolul de utilizator

149
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

Figura 6.11. Exemplu de rezolvare: rolul de administrator

150
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 7

ablonul de proiectare Metoda Fabric


1. Obiective 2. ablonul creaional Metoda Fabric 3. Exemplu de implementare 4. Motenirea i polimorfismul 5. Aplicaii

1. Obiective
Obiectivele capitolului 7 sunt urmtoarele: Implementarea unui program dup ablonul de proiectare Metoda Fabric (engl. Factory Method); Precizarea unor noiuni privind motenirea i polimorfismul (clase abstracte, interfee, membri virtuali), utilizate n majoritatea abloanelor de proiectare.

2. ablonul creaional Metoda Fabric


ablonul Metoda Fabric definete o interfa pentru crearea unui obiect, dar las subclasele s decid ce clas s instanieze. Diagrama de clase este prezentat n figura 7.1.

Figura 7.1. Diagrama de clase a ablonului Metoda Fabric


151
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

O alt diagram n care avem doi creatori i dou produse este prezentat n figura 7.2.

Figura 7.2. Diagrama de clase cu doi creatori i dou produse

Metoda Fabric se folosete n general atunci cnd o clas nu poate ti sau nu dorete s specifice din ce clas va fi creat un obiect i n consecin las clasele derivate s specifice clasa acestuia.

3. Exemplu de implementare
Codul C# corespunztor diagramei UML anterioare este prezentat mai jos. Clasele Produs
abstract class Product { } class ConcreteProductA : Product { } class ConcreteProductB : Product { }

152
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 7. ablonul de proiectare Metoda Fabric

Clasele Creator
abstract class Creator { // Metode abstract public Product FactoryMethod(); }

class ConcreteCreatorA : Creator { // Metode override public Product FactoryMethod() { return new ConcreteProductA(); } } class ConcreteCreatorB : Creator { // Metode override public Product FactoryMethod() { return new ConcreteProductB(); } }

Clientul
class Client { public static void Main( string[] args ) { // FactoryMethod returneaz ProductA Creator c = new ConcreteCreatorA(); Product p = c.FactoryMethod(); Console.WriteLine("A fost creat {0}", p ); // FactoryMethod returneaz ProductB c = new ConcreteCreatorB(); p = c.FactoryMethod(); Console.WriteLine("A fost creat {0}", p ); } }

153
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

4. Motenirea i polimorfismul
4.1. Polimorfismul
Cu ajutorul motenirii, o clas poate fi folosit ca i cum ar reprezenta mai multe tipuri. Ea poate fi folosit ca propriul su tip, ca un tip de clas de baz, sau un tip de interfa pe care o implementeaz. Acest comportament este numit polimorfism. n C#, orice tip este polimorfic. Un tip poate fi folosit aa cum este sau ca o instan de object, pentru c orice tip consider automat tipul object ca tip de baz. Polimorfismul este important nu numai pentru clasele derivate, ci i pentru clasele de baz. Cnd se folosete o clas de baz, se poate folosi de fapt orice clas derivat. Proiectanii unei clase de baz pot anticipa aspectele claselor care se vor modifica prin derivare. De exemplu, o clas de baz pentru maini poate conine membri care se modific dac maina este o dubi sau o main decapotabil. O clas de baz poate marca acei membri ca virtuali, dnd posibilitatea claselor derivate care reprezint maina decapotabil i dubia s suprascrie comportamentul respectiv. Cnd o clas derivat motenete o clas de baz, ea primete toate metodele, cmpurile, proprietile i evenimentele clasei de baz. Pentru a modifica datele i metodele unei clase de baz exist dou posibiliti: se poate nlocui clasa de baz cu una derivat sau se poate suprascrie un membru virtual din clasa de baz.

4.2. Clase abstracte


Cuvntul cheie abstract ofer posibilitatea crerii claselor i membrilor de clase doar pentru a putea fi motenii: pentru a defini trsturi ale claselor derivate, neabstracte.
public abstract class A { // membrii clasei }

O clas abstract nu poate fi instaniat. Scopul su este s ofere o definiie comun pentru mai multe clase derivate. De exemplu, o bibliotec de clase poate defini o clas abstract care este folosit ca parametru n mai

154
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 7. ablonul de proiectare Metoda Fabric

multe funcii din bibliotec i necesit ca dezvoltatorii care o folosesc s asigure o implementare proprie prin crearea unei clase derivate. Clasele abstracte pot de asemenea s defineasc metode abstracte, prin adugarea cuvntului cheie abstract n faa tipului returnat de metod. De exemplu:
public abstract class A { public abstract void Method(int i); }

Metodele abstracte nu au implementare i deci definiia metodei este urmat de ; n locul unui bloc normal de cod. Clasele derivate neabstracte trebuie s implementeze toate metodele abstracte.

4.3. Interfee
Interfeele sunt definite cu ajutorul cuvntului cheie interface. De exemplu:
interface IComparable { int CompareTo(object obj); }

Interfeele descriu un grup de funcionaliti asemntoare care pot s aparin oricrei clase sau structuri. Interfeele pot conine metode, proprieti, evenimente sau indeci, ns nu pot conine cmpuri. Membrii unei interfee sunt implicit publici. Clasele i structurile pot moteni interfee ntr-un mod asemntor claselor care motenesc clase sau structuri, cu dou excepii:

O clas sau structur poate moteni mai multe interfee; Cnd o clas sau structur motenete o interfa, motenete doar numele metodelor i semnturile acestora, deoarece interfeele nu conin implementri.

n exemplul urmtor, clasa Minivan este derivat din clasa Car i implementeaz interfaa IComparable.

155
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C# public class Minivan : Car, IComparable { public int CompareTo(object obj) { // implementarea metodei CompareTo return 0; // dac obiectele sunt egale } }

Pentru a implementa un membru al unei interfee, membrul respectiv trebuie s fie public, nestatic i s aib acelai nume i semntur cu membrul interfeei. Interfeele pot moteni alte interfee. Este posibil ca o clas s moteneasc o interfa de mai multe ori, printr-o clas sau interfa motenit. n acest caz, clasa poate implementa interfaa doar o dat. O interfa are urmtoarele caracteristici:

Este similar unei clase de baz abstracte: orice tip neabstract care motenete o interfa trebuie s i implementeze toi membrii; O interfa nu poate fi instaniat direct; Interfeele pot conine metode, proprieti, evenimente i indeci; Interfeele nu conin implementri ale metodelor; Clasele i structurile pot moteni mai multe interfee; O interfa poate ea nsi s moteneasc mai multe interfee.

4.4. Membri virtuali


Pentru ca o clas derivat s reimplementeze un membru al unei clase de baz, clasa de baz trebuie s defineasc membrul ca virtual iar clasa derivat s foloseasc cuvntul cheie override pentru a nlocui implementarea membrului. De exemplu:
public class BaseClass { public virtual void Method() { ... }

156
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 7. ablonul de proiectare Metoda Fabric public virtual int Property { get { ... } } } public class DerivedClass : BaseClass { public override void Method() { ... } public override int Property { get { ... } } }

Cmpurile nu pot fi virtuale, doar metodele, proprietile i indecii. Cnd o clas derivat suprascrie un membru virtual, acel membru este apelat chiar i atunci cnd o instan a acelei clase este accesat ca o instan a clasei de baz. De exemplu:
DerivedClass B = new DerivedClass(); B.Method (); // Apeleaz metoda nou BaseClass A = (BaseClass)B; A.Method (); // Apeleaz tot metoda nou

Un membru virtual rmne astfel n toat ierarhia de clase, indiferent de numrul de niveluri dintre clasa de baz i cea curent. Dac n clasa A este declarat un membru virtual i clasa B este derivat din clasa A iar clasa C este derivat din clasa B, atunci clasa C motenete membrul virtual i poate s l suprascrie, chiar dac n clasa B el a fost deja suprascris. De exemplu:
public class A { public virtual void Method() { ... } } 157
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C# public class B : A { public override void Method() { ... } } public class C : B { public override void Method() { ... } }

4.5. Clase sigilate i membri sigilai


Sigilarea mpiedic motenirea claselor sau suprascrierea membrilor virtuali. O clas pot fi declarat ca sigilat, punnd cuvntul cheie sealed naintea cuvntului class la definirea acesteia:
public sealed class A { // membrii clasei }

O clas sigilat nu poate fi folosit drept clas de baz. Din aceast cauz, ea nu poate fi nici abstract. Clasele sigilate sunt folosite, n principiu, pentru a preveni derivarea. Neputnd fi folosite ca i clase de baz, unele optimizri n timp real pot face apelul membrilor acestora mai rapid. Un membru, o metod, o proprietate sau un eveniment al unei clase derivate care suprascrie un membru virtual al clasei de baz poate declara acel membru ca sigilat. Astfel se elimin aspectul virtual al membrului pentru orice clas viitoare derivat. De exemplu:

158
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 7. ablonul de proiectare Metoda Fabric public class B { public virtual void Method() { ... } } public class C : B { public sealed override void Method() { ... } }

n exemplul anterior, metoda Method nu mai este virtual pentru nicio clas derivat din C. Dar este nc virtual pentru instanele clasei C.

4.6. nlocuirea unui membru cu ajutorul cuvntului cheie new


nlocuirea unui membru din clasa de baz cu unul nou, derivat, necesit folosirea cuvntului cheie new. Dac o clas de baz definete o metod, un cmp sau o proprietate, cuvntul cheie new se utilizeaz pentru a crea o nou definiie n clasa derivat. Cuvntul cheie new trebuie pus naintea tipului returnat al membrului clasei. De exemplu:
public class BaseClass { public void Method() { ... } public int Property { get { ... } } }

159
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C# public class DerivedClass : BaseClass { public new void Method() { ... } public new int Property { get { ... } } }

Cnd se folosete cuvntul cheie new, noul membru este apelat n locul celui vechi, nlocuit. Membrii respectivi ai clasei de baz sunt numii membri ascuni. Ei mai pot fi apelai doar dac o instan a clasei derivate este convertit prin cast la o instan a clasei de baz. De exemplu:
DerivedClass B = new DerivedClass(); B.Method (); // Apeleaz metoda nou BaseClass A = (BaseClass)B; A.Method (); // Apeleaz metoda veche

4.7. Accesarea clasei de baz cu ajutorul cuvntului cheie base


O clas derivat care a nlocuit sau suprascris o metod sau proprietate poate nc accesa metoda sau proprietatea din clasa de baz folosind cuvntul cheie base. De exemplu:
public class A { public virtual void Method() { ... } }

160
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 7. ablonul de proiectare Metoda Fabric public class B : A { public override void Method() { ... } } public class C : B { public override void Method() { // apeleaz Method din B pentru a utiliza comportamentul lui B base.Method(); // comportamentul specific lui C urmeaz n continuare ... } }

Se recomand ca un membru virtual s utilizeze cuvntul cheie base pentru a apela implementarea membrului din clasa de baz n implementarea proprie. Prin aceasta este lsat clasa derivat s se axeze pe implementarea propriilor funcionaliti. Dac nu este apelat implementarea din clasa de baz, atunci clasa derivat va trebui s se ocupe de implementarea unor funcionaliti similare cu acelea ale clasei de baz. Cuvntul cheie base este folosit:

Pentru a apela o metod din clasa de baz care a fost suprascris de o alt metod; Pentru a specifica clasa de baz al crei constructor s fie apelat la instanierea clasei derivate.

Din metodele statice nu este permis accesul la clasa de baz prin cuvntul cheie base.

5. Aplicaii
5.1. Realizai o aplicaie care deschide i afieaz fiiere text i grafice (figura 7.3). Testul se va efectua dup extensia fiierului (txt, rtf, bmp, jpg). Se va utiliza ablonul de proiectare Metoda fabric.
161
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

Figura 7.3. Exemplu de rezolvare: interfaa cu utilizatorul

Figura 7.4. Exemplu de rezolvare: fiierele de test


162
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 7. ablonul de proiectare Metoda Fabric

Aplicaia deschide fiiere index cu extensiile txd, pentru fiiere text, respectiv grd, pentru fiiere grafice. Aceste fiiere index conin cile ctre mai multe fiiere cu extensiile txt sau rtf, respectiv bmp sau jpg. Un exemplu privind structura de directoare i fiiere, precum i coninutul fiierelor index este prezentat n figura 7.4. Diagrama de clase este prezentat n figura 7.5.

Figura 7.5. Exemplu de rezolvare: diagrama de clase

Indicaii. Pentru citirea fiierelor text se poate utiliza clasa StreamReader din System.IO. Pentru fiierele text i rtf se poate utiliza clasa RichTextBox din System.Windows.Forms cu metoda LoadFile. Pentru
163
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

fiierele grafice se poate utiliza clasa Bitmap unde numele fiierului este primit n constructor sau proprietatea ImageLocation din clasa PictureBox. Pentru deschiderea unui fiier se utilizeaz un control OpenFileDialog. Pentru a se deschide doar tipurile de fiiere cu extensiile txd sau grd, se seteaz proprietatea Filter cu valoarea "Text documents (*.txd)|*.txd|Graphic documents (*.grd)|*.grd". n evenimentul corespunztor butonului Open, se poate prelucra un fiier doar dac utilizatorul a ales un fiier i a dat OK n fereastra de deschidere de fiiere.
if (openFileDialog.ShowDialog() != DialogResult.OK) return;

Apoi se testeaz valoarea proprietii FilterIndex din obiectul openFileDialog, care indic tipul de fiier deschis (index text sau index grafic). Indexul pleac de la 1, nu de la 0. n continuare, se instaniaz un obiect TextDocument sau un GraphicDocument. Afiarea paginilor n obiectul tabControl se poate face n modul urmtor:
Document doc; ... // crearea obiectului document (creatorul concret) tabControl.Controls.Clear(); foreach (Page p in doc.Pages) { TabPage tp = new TabPage(p.Name); p.Content.Dock = DockStyle.Fill; tp.Controls.Add(p.Content); tabControl.TabPages.Add(tp); }

Secvena de cod de mai sus se recomand a fi inclus ntr-un bloc de tratare a excepiilor, deoarece pot aprea probleme referitoare la deschiderea unui fiier care s nu conin ci valide sau fiierele indicate de aceste ci s nu aib coninutul ateptat. n produsele concrete se creeaz controalele corespunztoare iar numele paginilor afiate n tabControl se determin din numele fiierului ncrcat:
_name = Path.GetFileNameWithoutExtension(fileName);

164
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 7. ablonul de proiectare Metoda Fabric

n constructorul creatorului abstract (Document) se citete fiierul index linie cu linie i se creeaz paginile corespunztoare:
StreamReader sr = new StreamReader(indexFileName); string line; while ((line = sr.ReadLine()) != null) { if (line != string.Empty) _pages.Add(CreatePage(line)); } sr.Close();

ns deoarece metoda CreatePage este abstract, deciziile privind tipul efectiv al paginii vor fi luate de clasele derivate din Document. 5.2. Tem pentru acas. Adugai n proiect un nou tip de pagin care s afieze un document Microsoft Word i/sau un document PDF.

165
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

166
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 8

abloanele de proiectare Singleton i Prototip


1. Obiective 2. ablonul creaional Singleton 3. ablonul creaional Prototip 4. Aplicaii

1. Obiective
Obiectivele capitolului 8 sunt urmtoarele: Implementarea unui program dup ablonul de proiectare Singleton; Implementarea unui program dup ablonul de proiectare Prototip (engl. Prototype).

2. ablonul creaional Singleton


Scopul ablonului Singleton este s garanteze faptul c o clas poate avea doar o singur instan i s asigure un punct global de acces la ea. n unele situaii, este important ca o clas s aib o singur instan, de exemplu atunci cnd avem dispozitive hardware sau accesorii ataate unui calculator i dorim s prevenim accesul concurent la acestea. Alte situaii sunt cele n care se dorete lucrul cu registrul Windows (unic) sau atunci cnd se lucreaz cu un bazin (engl. pool) de fire de execuie. n general, ablonul este util cnd o resurs unic trebuie s aib un corespondent unic care o acceseaz din program. Este nevoie deci de o modalitate de a mpiedica instanierile multiple ale unei clase i de a asigura o metod unic global pentru accesarea instanei. Avantajul fa de utilizarea unor clase statice sau cu proprieti statice este faptul c Singleton-ul poate fi derivat i astfel clienii i pot extinde funcionalitatea fr a fi nevoii s modifice clasa existent. Diagrama de clase este prezentat n figura 8.1.

167
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

Figura 8.1. Diagrama de clase a ablonului Singleton

Clientul poate accesa poate accesa instana unic a clasei Singleton utiliznd metoda static Instance.

2.1. Exemplu de implementare


Codul C# corespunztor diagramei UML anterioare este prezentat mai jos. Clasa Singleton
class Singleton { private static Singleton _instance; private int _data; // datele propriu-zise ale clasei public int Data { get { return _data; } set { _data = value; } } private Singleton() // protected dac avem nevoie de clase derivate { } public static Singleton Instance() { // Iniializare ntrziat ("lazy initialization") if( _instance == null ) _instance = new Singleton(); return _instance; } }

168
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 8. abloanele de proiectare Singleton i Prototip

Clientul
public class Client { public static void Main() { // constructorul este privat, nu se poate folosi "new" Singleton s1 = Singleton.Instance(); s1.Data = 5; Singleton s2 = Singleton.Instance(); Console.WriteLine("Rezultat: {0}", s2.Data); // "Rezultat: 5" Console.ReadLine(); } }

Trebuie precizat c n situaiile n care mai multe fire de execuie pot accesa simultan seciunea de iniializare, trebuie incluse mecanisme suplimentare de sincronizare.

3. ablonul creaional Prototip


Scopul ablonului Prototip este s specifice tipurile de obiecte care pot fi create folosind o instan prototip i s creeze noi obiecte prin copierea acestui prototip. Exist situaii n care instanierea unui obiect n mod normal, folosind iniializarea strii interne n constructor, este costisitoare din punct de vedere al timpului sau resurselor de calcul. De aceea, dac este nevoie de mai multe astfel de obiecte n sistem, se poate utiliza un obiect prototip pentru a crea noi obiecte, prin copierea, n loc de calcularea de fiecare dat a valorilor datelor interne. Ideea de baz este utilizarea unei instane tipice pentru a crea o alt instan nrudit. ablonul folosete o metod caracteristic numit Clone pentru crearea cpiilor unui obiect. Nu se specific ns dac clonarea este superficial (engl. shallow) sau profund (engl. deep), aceasta depinde de tipul datelor copiate. Clonarea superficial este mai simpl i se folosete de obicei cnd cmpurile sunt de tip valoare (tipuri primitive, structuri). Pentru tipuri referin, acest tip de clonare copiaz doar referinele i de aceea, n aceste cazuri se poate prefera copierea profund, care copiaz recursiv toate valorile.
169
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

De exemplu, dac obiectul are dou cmpuri primitive, int i double, este suficient clonarea superficial. Dac se mai adaug un cmp vector, int[], clonarea superficial ar copia doar referina: obiectul prototip i copia ar referenia de fapt acelai vector. Clonarea profund creeaz n acest caz doi vectori distinci pentru cele dou obiecte. Una din principalele probleme ale ablonului este legat de tipul clonrii, deoarece varianta recomandat depinde de situaie. Diagrama de clase este cea din figura 8.2.

Figura 8.2. Diagrama de clase a ablonului Prototip

3.1. Exemplu de implementare


Codul C# corespunztor diagramei UML anterioare este prezentat mai jos. Prototipul abstract
abstract class Prototype { private string _data;

170
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 8. abloanele de proiectare Singleton i Prototip public Prototype(string data) { _data = data; } public string Data { get { return _data; } } abstract public Prototype Clone(); }

Prototipurile concrete
class ConcretePrototype1 : Prototype { public ConcretePrototype1(string data) : base(data) { } override public Prototype Clone() { // copie superficial return (Prototype)this.MemberwiseClone(); } }

class ConcretePrototype2 : Prototype { public ConcretePrototype2(string data) : base(data) { } override public Prototype Clone() { // copie superficial return (Prototype)this.MemberwiseClone(); } }

171
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

Clientul
class Client { public static void Main(string[] args) { // se creeaz dou prototipuri i se cloneaz fiecare ConcretePrototype1 prototype1 = new ConcretePrototype1("Proto1"); ConcretePrototype1 clone1 = (ConcretePrototype1)p1.Clone(); Console.WriteLine("Cloned: {0}", c1.Data); ConcretePrototype2 prototype2 = new ConcretePrototype2("Proto2"); ConcretePrototype2 clone2 = (ConcretePrototype2)p2.Clone(); Console.WriteLine("Cloned: {0}", c2.Data); Console.ReadLine(); } }

4. Aplicaii
4.1. S se simuleze lucrul cu o imprimant (figura 8.3). Fiecrui document i este asociat o mrime. Imprimanta are o coad de documente ce urmeaz a fi tiprite. Cnd se trimite un document la imprimare, dac aceast coad este vid, fiierul ncepe s fie tiprit. Timpul necesar tipririi este proporional cu mrimea sa. Cnd coada imprimantei nu este vid, documentul este doar introdus n coad. La terminarea tipririi unui document, se preia urmtorul din coad (dac exist). Implementarea se va realiza utiliznd ablonul Singleton. Diagrama de clase a aplicaiei este prezentat n figura 8.4. Indicaie: pentru simularea tipririi se recomand folosirea unui control Timer, descris n capitolul 2, seciunea 5. Evenimentul Tick este tratat o dat la un interval de timp, specificat n milisecunde de proprietatea Interval. De exemplu, dac Interval = 500, codul evenimentului Tick va fi executat n mod repetat, de dou ori pe secund. Proprietatea Enabled arat dac timer-ul e activat sau nu (true/false).

172
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 8. abloanele de proiectare Singleton i Prototip

Figura 8.3. Exemplu de rezolvare: interfaa cu utilizatorul

Figura 8.4. Exemplu de rezolvare: diagrama de clase

Proprietatea Queue din clasa Printer returneaz coninutul cozii de activiti ale imprimantei, pentru a fi afiat ca atare de client (MainForm). n acest fel, clientul nu mai trebuie s depind de clasa DocInfo, care reprezint obiectele cu care lucreaz intern doar clasa Printer.

173
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

4.2. S presupunem c avem un joc n care utilizatorul mpuc montri pe ecran (figura 8.5). Exist mai multe tipuri de montri, fiecare cu propriile caracteristici: imagine, culoare, numr de viei etc. Pe lng acestea, fiecare monstru are implementat un modul de inteligen artificial, a crui iniializare necesit multe resurse.

Figura 8.5. Exemplu de rezolvare: interfaa cu utilizatorul

Scheletul programului este dat, la fel i o clas pentru un monstru implementat n MonsterSprite.dll, cu structura din diagrama din figura 8.6 i al crei cod surs este prezentat n continuare.

Figura 8.6. Diagrama claselor din DLL


174
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 8. abloanele de proiectare Singleton i Prototip

MonsterSprite.cs
using System; using System.Drawing; using System.Threading; using System.Windows.Forms; using System.Runtime.Serialization; namespace Monster { [Serializable] public class MonsterSprite { protected Bitmap _image; protected Color _color; protected int _lives; protected int _maxLives; protected string _ai = "I am stupid"; public MonsterSprite(Monster settings) { _image = new Bitmap(settings.Image); _maxLives = Convert.ToInt32(settings.Lives); _lives = _maxLives; _color = GetColor(settings.Color); InitAI(); } /// <summary> /// Interpreteaz numele unei culori i returneaz un obiect Color /// </summary> /// <param name="colorName"></param> /// <returns></returns> protected Color GetColor(string colorName) { Color c; switch (colorName) { case "red": c = Color.Red; break; case "blue": c = Color.Blue; break; case "green": c = Color.Green; break; case "yellow": c = Color.Yellow; break; case "orange": c = Color.Orange; break; case "black": c = Color.Black; break;

175
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C# default: c = Color.Gray; break; } return c; } private void InitAI() { _ai = "I am smart"; MessageBox.Show("Se initializeaza modulul de inteligenta artificiala..."); Thread.Sleep(2000); } /// <summary> /// Deseneaz un personaj /// </summary> /// <param name="g"></param> /// <param name="x"></param> /// <param name="y"></param> public void Draw(Graphics g, int x, int y) { g.DrawImage(_image, x, y); double more = (double)_lives / (double)_maxLives; g.FillRectangle(new SolidBrush(Color.DarkGray), (float)x, (float)(y + 200), (float)200, (float)4); g.FillRectangle(new SolidBrush(_color), (float)x, (float)(y + 200), (float)(more * 200), (float)4); } /// <summary> /// Returneaz true dac este mort /// </summary> /// <returns></returns> public bool Shoot() { _lives--; if (_lives == 0) return true; else return false; } } }

176
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 8. abloanele de proiectare Singleton i Prototip

Utils.cs
namespace Monster { public class AllMonsters { public Monster[] Monsters; } public class Monster { public string Image; public string Color; public string Lives; } }

Scopul aplicaiei este s evitai iniializarea de fiecare dat a modulului costisitor de IA (metoda InitAI), nlocuind instanierea unui obiect MonsterSprite cu clonarea sa i modificarea caracteristicilor variabile. n acest caz, va exista un PrototypeManager care va asigura crearea montrilor, nlocuind o instruciune de tipul:
_mainMonster = new MonsterSprite(_listMonsters[_monsterType]);

cu:
_mainMonster = _prototypeManager.GetMonster(_monsterType);

DLL-ul coninnd clasa MonsterSprite se va folosi ca atare, fr modificri. Indicaie: pentru a face rapid o copie profund a unui obiect, se poate utiliza serializarea ntr-o metod de tipul:
public static object Clone(object obj) { object objClone = null; MemoryStream memory = new MemoryStream(); BinaryFormatter binForm = new BinaryFormatter(); binForm.Serialize(memory, obj); memory.Position = 0; objClone = binForm.Deserialize(memory); return objClone; }

177
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

n vederea utilizrii acestei modaliti de copiere, trebuie incluse n proiect namespace-urile System.Runtime.Serialization i System.IO, iar clasa trebuie decorat cu atributul [Serializable]. Aceast metod general trebuie particularizat la situaia concret a aplicaiei. n continuare, se prezint scheletul programului, care trebuie optimizat dup cerinele precizate mai sus. MainForm.cs
using System; using System.Collections.Generic; using System.Drawing; using System.Windows.Forms; using System.Xml; using System.Xml.Serialization; using System.IO; namespace Monster { public partial class MainForm : Form { List<Monster> _listMonsters; MonsterSprite _mainMonster; Random _rand = new Random(); int _monsterType = 0; int _x, _y; long _elapsed; const int MonsterSize = 200; const int MaxLevels = 4; bool _gameOver = false; public MainForm() { InitializeComponent(); } private void loadSettingsToolStripMenuItem_Click(object sender, EventArgs e) { // ncarc try { XmlSerializer serializer = new XmlSerializer(typeof(AllMonsters)); FileStream fs = new FileStream("settings.xml", FileMode.Open); XmlReader reader = new XmlTextReader(fs); AllMonsters ab = (AllMonsters)serializer.Deserialize(reader); 178
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 8. abloanele de proiectare Singleton i Prototip reader.Close(); fs.Close(); serializer = null; _listMonsters = new List<Monster>(); for (int i = 0; i < ab.Monsters.Length; i++) _listMonsters.Add(ab.Monsters[i]); } catch { MessageBox.Show("Nu s-a putut incarca settings.xml"); return; } if (_listMonsters == null || _listMonsters.Count == 0) { MessageBox.Show("Fisier de configurare invalid: settings.xml"); _listMonsters = null; return; } } private void startNewGameToolStripMenuItem_Click(object sender, EventArgs e) { // start if (_listMonsters == null || _listMonsters.Count == 0) loadSettingsToolStripMenuItem.PerformClick(); if (_listMonsters == null) return; _monsterType = 0; _gameOver = false; try { _mainMonster = new MonsterSprite(_listMonsters[_monsterType]); } catch (Exception exc) { MessageBox.Show(exc.Message); _mainMonster = null; return; }

179
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C# _elapsed = DateTime.Now.Ticks; timer.Start(); Redraw(); } private void Redraw() { try { _x = _rand.Next(pictureBox.Width - MonsterSize + 20); _y = _rand.Next(pictureBox.Height - MonsterSize - 10); pictureBox.Refresh(); } catch { MessageBox.Show("Fereastra este prea mica"); _mainMonster = null; return; } } private void exitToolStripMenuItem_Click(object sender, EventArgs e) { Close(); } private void aboutToolStripMenuItem_Click(object sender, EventArgs e) { // despre program const string copyright = "Sablonul de proiectare Prototip\r\n" + "Ingineria programarii\r\n" + "(c) 2008-2012 Florin Leon\r\n" + " http://florinleon.byethost24.com/lab_ip.htm "; MessageBox.Show(copyright, "Despre Monstri"); } private void pictureBox_Paint(object sender, PaintEventArgs e) { if (_mainMonster == null) { timer.Stop(); 180
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 8. abloanele de proiectare Singleton i Prototip e.Graphics.Clear(Color.White); if (_gameOver) { e.Graphics.DrawString("Jocul s-a terminat!", new Font("Arial", 48), Brushes.Red, 10, 10); long dt = DateTime.Now.Ticks - _elapsed; double ms = dt / 10000000.0; e.Graphics.DrawString(ms.ToString("F3") + " s", new Font("Arial", 48), Brushes.Red, 10, 80); } return; } _mainMonster.Draw(e.Graphics, _x, _y); } private void ShootMonster() { if (_mainMonster.Shoot()) { _monsterType++; if (_monsterType < MaxLevels) { try { _mainMonster = new MonsterSprite(_listMonsters[_monsterType]); } catch (Exception exc) { MessageBox.Show(exc.Message); _mainMonster = null; return; } Redraw(); } else { _mainMonster = null; _gameOver = true; pictureBox.Refresh(); } } else Redraw(); } 181
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C# private void pictureBox_MouseDown(object sender, MouseEventArgs e) { if (_mainMonster != null) { if (e.X > _x && e.X < _x + MonsterSize && e.Y > _y && e.Y < _y + MonsterSize) ShootMonster(); } } private void timer_Tick(object sender, EventArgs e) { Graphics g = pictureBox.CreateGraphics(); long dt = DateTime.Now.Ticks - _elapsed; double ms = dt / 10000000.0; g.FillRectangle(Brushes.White, 1, 1, 100, 20); g.DrawString(ms.ToString("F3") + " s", new Font("Arial", 10), Brushes.Black, 1, 1); } private void Form1_Load(object sender, EventArgs e) { this.WindowState = FormWindowState.Maximized; } } }

Un exemplu de fiier cu setri este dat mai jos. settings.xml


<?xml version="1.0" encoding="us-ascii"?> <AllMonsters> <Monsters> <Monster> <Image>monster1.jpg</Image> <Color>blue</Color> <Lives>3</Lives> </Monster> <Monster> <Image>monster2.jpg</Image> <Color>green</Color> <Lives>3</Lives> </Monster>

182
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 8. abloanele de proiectare Singleton i Prototip <Monster> <Image>monster3.jpg</Image> <Color>black</Color> <Lives>4</Lives> </Monster> <Monster> <Image>monster4.jpg</Image> <Color>red</Color> <Lives>5</Lives> </Monster> </Monsters> </AllMonsters>

183
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

184
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 9

ablonul de proiectare Faad


1. Obiectiv 2. Scop i motivaie 3. Aplicabilitate 4. Analiza ablonului 5. Exemplu de implementare 6. Aplicaie

1. Obiectiv
Obiectivul capitolului 9 este implementarea unui program dup ablonul de proiectare structural Faad (engl. Faade).

2. Scop i motivaie
ablonul Faad asigur o interfa unitar pentru o mulime de interfee ale unui subsistem. Faada definete o interfa de nivel nalt care face subsistemul mai uor de utilizat. Structurarea unui sistem n subsisteme reduce complexitatea. Unul din scopurile unei proiectri corecte este acela de a minimiza comunicaiile i dependenele dintre subsisteme. Un mod de a obine aceasta este introducerea faadei, obiect care furnizeaz o singur interfa simplificat pentru funcionalitile mai generale ale subsistemului. De exemplu, putem considera un mediu de programare care d aplicaiilor acces ctre un subsistem de compilare ce conine clase precum Scanner, Parser, ProgramNode, BytecodeStream i ProgramNodeBuilder (figura 9.1). Unele aplicaii specializate ar putea avea nevoie s acceseze aceste clase direct, dar majoritatea aplicaiilor care folosesc compilatorul nu sunt interesate de detalii precum parsarea sau generarea de cod, ci doresc doar s compileze un program. Interfeele puternice dar de nivel sczut din subsistemul compilator le complic sarcina. Pentru a asigura o interfa de nivel nalt care s separe clienii de aceste clase, subsistemul compilator include de asemenea o clas Compiler. Aceast clas definete o interfa unitar pentru funcionalitatea
185
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

compilatorului i se comport ca o faad, oferind clientului o interfa simplificat pentru subsistemul compilator.

Figura 9.1. Exemplu de sistem complex apelabil prin intermediul unei Faade

3. Aplicabilitate
Faadele se folosesc atunci cnd se dorete furnizarea unei interfee simple pentru un sistem complex. Pe msur ce evolueaz, sistemele devin de obicei din ce n ce mai complexe. Atunci cnd sunt folosite, majoritatea modelelor sunt completate cu numeroase clase suplimentare, ceea ce face sistemul mai uor de personalizat, dar de asemenea devine tot mai greu de utilizat pentru clienii care nu au nevoie s l personalizeze. O faad poate furniza o interfa implicit simpl a subsistemului, suficient de bun pentru majoritatea clienilor. Doar clienii care au nevoie de mai mult flexibilitate trebuie s utilizeze direct clasele subsistemului din spatele faadei. De asemenea, un astfel de subsistem conine de multe ori interdependene complexe. Folosirea sa ca atare ar crete cuplarea dintre codul clientului i elementele subsistemului. Faada decupleaz subsistemul de clieni, deoarece n acest caz clienii depind numai de faad.
186
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 9. ablonul de proiectare Faad

Utilizarea ablonului poate ajuta i structurarea pe niveluri a subsistemelor, folosind cte o faad pentru a defini cte un punct de intrare pentru fiecare nivel al subsistemului. Dac nivelurile subsistemului comunic doar prin faade, cuplarea dintre ele va scdea de asemenea.

4. Analiza ablonului
Structura ablonului Faad este prezentat n figura 9.2.

Figura 9.2. Structura ablonului Faad

Considernd din nou elementele subsistemului compilator, pentru exemplificare, participanii ablonului sunt: Faada (Compiler) o tie ce funcionaliti implementeaz clasele subsistemului; o Trimite cererile clientului ctre obiectele subsistemului; Clasele subsistemului (Scanner, Parser, ProgrameNode etc.) o Implementeaz funcionalitatea subsistemului; o Primesc apeluri de la obiectul Faad; o Nu au cunotin despre Faad; apelurile sunt unidirecionale: doar dinspre Faad ctre subsistem.

Clienii comunic cu subsistemul trimind cereri faadei, care le trimite mai departe ctre obiectele subsistemului ce ndeplinesc efectiv sarcinile. Faada trebuie s gestioneze interfaa cu clientul i s cunoasc interfeele subsistemului. Clienii care utilizeaz faada nu au nevoie s acceseze obiectele subsistemului, ns acestea nu sunt ascunse. Rmne la latitudinea clientului dac dorete s utilizeze interfaa simplificat a faadei sau s apeleze direct funcionalitile de nivel sczut ale obiectelor subsistemului.
187
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

5. Exemplu de implementare
Codul C# corespunztor structurii ablonului Faad este prezentat mai jos. Subsistemele
class SubsystemOne { public void MethodOne() { Console.WriteLine("Metoda subsistemului 1 "); } } class SubsystemTwo { public void MethodTwo() { Console.WriteLine("Metoda subsistemului 2"); } } class SubsystemThree { public void MethodThree() { Console.WriteLine("Metoda subsistemului 3"); } } class SubsystemFour { public void MethodFour() { Console.WriteLine("Metoda subsistemului 4"); } }

188
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 9. ablonul de proiectare Faad

Faada
class Facade { SubSystemOne _one; SubSystemTwo _two; SubSystemThree _three; SubSystemFour _four; public Facade() { _one = new SubSystemOne(); _two = new SubSystemTwo(); _three = new SubSystemThree(); _four = new SubSystemFour(); } public void MethodA() { Console.WriteLine("Metoda A a Fatadei"); _one.MethodOne(); _two.MethodTwo(); _four.MethodFour(); } public void MethodB() { Console.WriteLine("Metoda B a Fatadei"); _two.MethodTwo(); _three.MethodThree(); } }

Clientul
public class Client { public static void Main(string[] args) { Facade f = new Facade(); f.MethodA(); f.MethodB(); Console.ReadLine(); } }

189
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

6. Aplicaie
6.1. S se realizeze simularea unei comenzi de cumprare online a unor produse. Exist clase pentru activiti precum nregistrarea cererii, facturare, expediere, statistici privind cumprtorii. Clasa Facade se constituie ntr-un punct de intrare unic pentru toate aceste activiti. Indicaii. Diagrama de clase a aplicaiei este prezentat n figura 9.3. Pentru iniializarea controlului checkedListBox din fereastra principal se pot utiliza n constructor numele produselor furnizate de clasa InfoProduse. Deoarece dorim s decuplm clientul (MainForm) de clasele sistemului, numele sunt primite tot prin intermediul Faadei:
public MainForm() { InitializeComponent(); string[] produse = Facade.Produse(); for (int i = 0; i < produse.Length; i++) checkedListBoxProduse.Items.Add(produse[i], false); }

n evenimentul de apsare a butonului se valideaz (opional) CNP-ul prin intermediul metodei statice a Faadei, apoi se instaniaz o Faad cu datele citite din text-box-urile ferestrei principale i se proceseaz comanda. O comand nu trebuie facturat i expediat dac nu s-a comandat niciun produs. Pentru statistici, se prelucreaz codul numeric personal: SAALLZZJJNNNC, unde prima cifr reprezint sexul (impar = M, par = F), urmtoarele 6 cifre reprezint data naterii (an, lun, zi), urmtoarele 2 cifre reprezint codul judeului, urmtoarele 3 indic numrul de ordine din registrul strii civile iar ultima e cifra de control. Persoanele nscute ntre 1900-1999 au prima cifr 1 sau 2, iar cele nscute dup 2000 au prima cifr 5 sau 6. Validarea CNP-ului se poate face ntr-o metod de tipul:
private bool CNPValid() { string cnp = textBoxCNP.Text; if (cnp.Length != 13) return false;

190
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 9. ablonul de proiectare Faad

191
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Figura 9.3. Exemplu de rezolvare: diagrama de clase

Florin Leon Aplicaii de ingineria programrii n C# int suma = Convert.ToInt32(cnp[0].ToString()) * 2 + Convert.ToInt32(cnp[1].ToString()) * 7 + Convert.ToInt32(cnp[2].ToString()) * 9 + Convert.ToInt32(cnp[3].ToString()) * 1 + Convert.ToInt32(cnp[4].ToString()) * 4 + Convert.ToInt32(cnp[5].ToString()) * 6 + Convert.ToInt32(cnp[6].ToString()) * 3 + Convert.ToInt32(cnp[7].ToString()) * 5 + Convert.ToInt32(cnp[8].ToString()) * 8 + Convert.ToInt32(cnp[9].ToString()) * 2 + Convert.ToInt32(cnp[10].ToString()) * 7 + Convert.ToInt32(cnp[11].ToString()) * 9; int rest = suma % 11; if ((rest < 10) && (rest.ToString() == cnp[12].ToString()) || (rest == 10) && (cnp[12] == '1')) return true; return false; }

Interfaa cu utilizatorul poate arta ca n figura 9.4.

Figura 9.4. Exemplu de rezolvare: diagrama de clase

192
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 10

ablonul de proiectare Proxy


1. Obiectiv 2. Scop i motivaie 3. Aplicabilitate 4. Analiza ablonului 5. Exemplu de implementare 6. Aplicaii

1. Obiectiv
Obiectivul capitolului 10 este implementarea unui program dup ablonul de proiectare structural Proxy (o traducere posibil ar fi Intermediar sau Delegare). Vom considera varianta proxy-ului de protecie pentru stabilirea drepturilor de acces la nite documente protejate. Tema pentru acas completeaz ablonul cu varianta proxy-ului la distan, pentru accesarea distribuit a documentelor.

2. Scop i motivaie
ablonul Proxy asigur un nlocuitor pentru alt obiect pentru a controla accesul la acesta. Unul din motivele pentru controlarea accesului la un obiect este ntrzierea crerii i iniializrii lui pn n momentul n care acesta trebuie utilizat. De exemplu, s considerm un program de editare de documente care poate conine obiecte grafice. Crearea unor obiecte-imagine raster de mari dimensiuni poate fi foarte costisitoare din punct de vedere al timpului necesar citirii fiierelor de pe harddisk, mai ales dac presupunem c sunt stocate n format bmp. Deschiderea unui document trebuie s fie ns o operaie rapid, deci crearea tuturor acestor obiecte costisitoare odat cu deschiderea documentului trebuie evitat. Acest lucru nici nu este necesar, deoarece nu toate imaginile vor fi vizibile n acelai timp. O soluie este crearea la cerere a fiecrui obiect costisitor, n cazul nostru acest lucru avnd loc n momentul n care o imagine devine vizibil.

193
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

Se pune problema ce vom plasa n document n locul imaginii reale i cum putem ascunde faptul c imaginea este creat la cerere, astfel nct s nu complicm implementarea editorului iar optimizarea s nu afecteze codul de formatare i redare a imaginilor. Se poate utiliza un alt obiect, un proxy de imagine, care s acioneze ca nlocuitor al imaginii reale. Obiectul proxy acioneaz la fel ca imaginea i o instaniaz cnd este nevoie, adic doar atunci cnd programul de editare i cere s o afieze. Cererile ulterioare sunt transmise direct ctre imaginea real i deci proxy-ul trebuie s aib o referin ctre aceasta (figura 10.1).

Figura 10.1. Diagrama de clase a unui proxy de imagine

Referina la obiectul _image din ImageProxy va fi nul pn n momentul n care editorul apeleaz metoda Draw i obiectul proxy instaniaz imaginea real. Operaia Draw asigur faptul c imaginea este instaniat nainte de a fi apelat obiectul Image. Pn atunci, dac mai exist o metod GetSize care returneaz dimensiunile imaginii, obiectul ImageProxy poate returna o valoare proprie implicit. Dup instanierea imaginii raster, obiectul ImageProxy va returna dimensiunile reale ale imaginii apelnd metoda GetSize din Image.

3. Aplicabilitate
ablonul Proxy poate fi aplicat oriunde este nevoie de o referin mai sofisticat la un obiect. Sunt prezentate n continuare cteva situaii n care se poate aplica acest ablon:
194
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 10. ablonul de proiectare Proxy

Proxy-ul la distan (engl. remote proxy) reprezint un obiect local care intermediaz accesul la un obiect de pe o alt main. Este util n general pentru aplicaiile distribuite; Proxy-ul virtual (engl. virtual proxy) creeaz la cerere obiecte costisitoare. Un exemplu este clasa ImageProxy din seciunea anterioar. Imaginea real poate fi ns i o imagine descrcat de pe internet; n acest caz proxy-ul poate afia o imagine temporar pn cnd este descrcat imaginea real. ablonul nu se refer doar la imagini, ci la orice obiect a crui creare necesit timp sau resurse importante; Proxy-ul de protecie (engl. protection proxy) controleaz accesul la obiectul real. Este util atunci cnd obiectul reprezentat presupune drepturi diferite de acces; Referina inteligent (engl. smart reference) este un nlocuitor pentru o referin, care efectueaz aciuni suplimentare n momentul accesrii unui obiect. De exemplu, se poate folosi pentru pstrarea cpiilor unor obiecte mari care pot sau nu s se modifice. Dac se dorete crearea unei alte instane de acest tip, proxy-ul poate decide s nu fac efectiv copia, folosind n continuare primul obiect. Dac clientul ncearc s fac modificri n al doilea obiect, proxy-ul face abia atunci copia i modificrile. De asemenea, se poate stabili astfel numrul de referine ctre obiectul real, astfel nct acesta s poat fi automat eliberat atunci cnd nu mai exist referine.

4. Analiza ablonului
Diagrama generic de clase a ablonului Proxy este prezentat n figura 10.2.

Figura 10.2. Diagrama de clase a ablonului Proxy


195
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

Trebuie precizat c att clasa Proxy ct i clasa RealSubject au o interfa identic, definit de clasa Subject, astfel nct un obiect proxy s poat fi nlocuit de obiectul real. n funcie de tipul su, obiectul Proxy trimite apelurile ctre obiectul RealSubject.

5. Exemplu de implementare
Codul C# corespunztor structurii ablonului Proxy este prezentat mai jos. Subiectul abstract
abstract class Subject { // Metode abstract public void Request(); }

Subiectul real
class RealSubject : Subject { // Metode override public void Request() { Console.WriteLine("Apelul din subiectul real"); } }

Proxy
class Proxy : Subject { RealSubject _realSubject; override public void Request() { // Se folosete iniializarea ntrziat if (_realSubject == null) _realSubject = new RealSubject();

196
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 10. ablonul de proiectare Proxy _realSubject.Request(); } }

Clientul
public class Client { public static void Main(string[] args) { // Se creeaz un proxy i se apeleaz metoda dorit Proxy p = new Proxy(); p.Request(); } }

6. Aplicaii
6.1. Realizai un program pentru accesul la o serie de documente potrivit nivelului de acces al utilizatorului. Un schelet al aplicaiei pentru construirea interfaei grafice cu utilizatorul (prezentat n figura 10.3) i fiierele de configurare sunt incluse dup descrierea cerinelor i indicaiilor.

Figura 10.3. Exemplu de rezolvare: interfaa cu utilizatorul


197
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

Structur propus de fiiere este prezentat n figura 10.4.

Figura 10.4. Structura de fiiere a aplicaiei

Nivelurile de acces se dau n fiierul niveluri.txt:


Public Privat Confidential Secret

Lista de utilizatori se gsete n fiierul utilizatori.txt, care este de forma specificat n tabelul 10.1.
Tabelul 10.1. Exemplu de list de utilizatori
Numele utilizatorului admin pu pr se co Hash-ul parolei 0DPiKuNIrrVmD8IUCuw1hQxNqZc= 8DqjUKTMEIhL2P06I5dcoOT+yDA= VJjZuW7Sgy4EqQxKwqtx+Gmyv9w= AHYsz6cDOT4Nr/gTpuzBn3zQJCE= h92iBBZknypqGwPU4T1IqAsaNX8= 198
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Nivelul de acces -1 0 1 3 2

Capitolul 10. ablonul de proiectare Proxy

Pe prima coloan este numele utilizatorului. Pe coloana a doua este hash-ul parolei, pentru evitarea stocrii n clar a acesteia. La autentificare, se va calcula hash-ul parolei i se va compara cu hash-ul din fiier. Pe a treia coloan se noteaz nivelul de acces. Administratorul este un tip special de utilizator. Acesta nu poate consulta documente, dar poate aduga utilizatori. Iniial, numele administratorului este admin i parola este tot admin. n situaia de mai sus, parolele utilizatorilor sunt egale cu numele lor. n program, la autentificarea unui utilizator se verific existena utilizatorului i corectitudinea parolei. Documentele din directorul Documente au asociate i ele drepturi de acces, setate n fiierul drepturi.txt:
public1.rtf public2.rtf privat1.rtf privat2.rtf confidential.rtf topsecret.rtf

Pe prima linie sunt documentele corespunztoare primului nivelul de acces (Public), pe linia a doua documentele pentru nivelul Privat .a.m.d. Cnd un utilizator se autentific, el primete lista documentelor de pe nivelul su de acces dar i documentele de pe nivelurile inferioare. Se presupune c serverul de documente ar fi pe alt main. La selectarea unui document, acesta este criptat i trimis clientului care l decripteaz i l afieaz. Accesul la documente se va face printr-un proxy de protecie. Acesta la rndul su acceseaz managerul real de documente. Clasele ProxyDocumentManager i RealDocumentManager vor implementa ambele interfaa IDocumentManager. Diagrama de clase a aplicaiei este prezentat n figura 10.5.

199
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

Figura 10.5. Exemplu de rezolvare: diagrama de clase

ProxyDocumentManager se ocup de autentificare i gestionarea drepturilor de acces. Metodele GetDocumentList i GetDocument apeleaz metodele corespunztoare din RealDocumentManager. RealDocumentManager cripteaz documentul i l trimite ctre ProxyDocumentManager. Aceast operaie este important mai ales atunci cnd ProxyDocumentManager i RealDocumentManager se afl pe maini diferite (situaia de la tem). Atunci cnd ProxyDocumentManager primete documentul, i afieaz coninutul criptat n EncryptedDocForm. Este o operaie opional, util doar pentru a vedea mai clar aspectul unui fiier binar transformat ca string n baza 64, prin apelul metodei ToBase64String. Pentru a nu incomoda, aceast fereastr secundar poate fi implicit minimizat:
_encryptedDocForm = new EncryptedDocForm(encryptedFile); _encryptedDocForm.WindowState = FormWindowState.Minimized; _encryptedDocForm.Show();

200
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 10. ablonul de proiectare Proxy

n vederea afirii documentului decriptat ntr-un control de tip RichTextBox de ctre MainForm, se utilizeaz proprietatea Rtf a controlului, de exemplu: richTextBox.Rtf = decryptedRtfDoc. Pentru a v putea concentra exclusiv asupra aplicrii ablonului, n continuare se dau cteva clase ce urmeaz a fi completate sau utilizate n program. MainForm.cs
namespace ProtectionProxy { public partial class MainForm : Form { private ProxyDocumentManager _proxyDocumentManager; public MainForm() { InitializeComponent(); groupBoxAdmin.Enabled = false; _proxyDocumentManager = new ProxyDocumentManager(); } } }

DocumentManager.cs
namespace ProtectionProxy { interface IDocumentManager { List<string> GetDocumentList(); string GetDocument(string documentName, string encryptionPassword); } }

ProxyDocumentManager.cs
namespace ProtectionProxy { public class ProxyDocumentManager : IDocumentManager { private RealDocumentManager _realDocumentManager; private List<User> _users;

201
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C# private List<string> _levels; private const string Path = "Secure\\"; public struct User { public readonly string Name; public readonly string PassHash; public readonly int AccessLevel; public User(string name, string passHash, int accessLevel) { Name = name; PassHash = passHash; AccessLevel = accessLevel; } } public ProxyDocumentManager() { _levels = new List<string>(); StreamReader sr = new StreamReader(Path + "niveluri.txt"); string[] lvls = sr.ReadToEnd().Split(" \t\r\n".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); sr.Close(); for (int i = 0; i < lvls.Length; i++) _levels.Add(lvls[i]); _users = new List<User>(); sr = new StreamReader(Path + "utilizatori.txt"); string line; while ((line = sr.ReadLine()) != null) { string[] toks = line.Split('\t'); User user = new User(toks[0], toks[1], Convert.ToInt32(toks[2])); _users.Add(user); } sr.Close(); } #region IDocumentManager Members public List<string> GetDocumentList() { throw new Exception("The method or operation is not implemented."); } 202
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 10. ablonul de proiectare Proxy public string GetDocument(string documentName, string encryptionPassword) { throw new Exception("The method or operation is not implemented."); } #endregion } }

RealDocumentManager.cs
namespace ProtectionProxy { class RealDocumentManager : IDocumentManager { private static List<List<string>> _documents; private const string Path = "Secure\\", DocPath = "Secure\\Documente\\"; static RealDocumentManager() { int numberOfLevels = 0; StreamReader sr = new StreamReader(Path + "drepturi.txt"); string[] lines = sr.ReadToEnd().Split("\r\n".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); sr.Close(); numberOfLevels = lines.Length; _documents = new List<List<string>>(numberOfLevels); for (int i = 0; i < numberOfLevels; i++) _documents.Add(new List<string>()); sr = new StreamReader(Path + "drepturi.txt"); for (int i = 0; i < numberOfLevels; i++) { string[] files = sr.ReadLine().Split(); for (int j = i; j < numberOfLevels; j++) { for (int k = 0; k < files.Length; k++) _documents[j].Add(files[k]); } } sr.Close(); }

203
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C# #region IDocumentManager Members public List<string> GetDocumentList() { throw new Exception("The method or operation is not implemented."); } public string GetDocument(string documentName, string encryptionPassword) { throw new Exception("The method or operation is not implemented."); } #endregion } }

Observaii: parola pentru criptarea unui documentului transmis se poate considera cunoscut de ctre ProxyDocumentManager i RealDocumentManager, astfel nct s nu mai apar ca parametru n metoda GetDocument (encryptionPassword). Stabilirea n mod dinamic a unei parole comune ntre dou entiti care comunic printr-un canal public este o problem n sine i nu poate fi tratat aici. De asemenea, parola folosit pentru criptarea documentelor este diferit de parola utilizatorului i nici nu trebuie s fie cunoscut de ctre acesta. Constructorul static al clasei RealDocumentManager asigur faptul c listele cu drepturile de acces vor fi iniializate o singur dat nainte de utilizarea efectiv a clasei de ctre ProxyDocumentManager. Constructorul static este apelat automat nainte de a fi creat prima instan a clasei sau nainte de referenierea membrilor statici. Cryptography.cs
/************************************************************************** * Website: http://www.obviex.com/samples/Encryption.aspx * * Adaptation and added functionality by Florin Leon * * http://florinleon.byethost24.com/lab_ip.htm * * Description: Contains functions for encryption, decryption, * * and hashing. * **************************************************************************/

using System; using System.Security.Cryptography; using System.IO; using System.Text;

204
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 10. ablonul de proiectare Proxy namespace ProtectionProxy { public class Cryptography { /// <summary> /// Encrypts specified plaintext using Rijndael symmetric key algorithm /// and returns a base64-encoded result. /// </summary> /// <param name="plainText"> /// Plaintext value to be encrypted. /// </param> /// <param name="passPhrase"> /// Passphrase from which a pseudo-random password will be derived. The /// derived password will be used to generate the encryption key. /// Passphrase can be any string. In this example we assume that this /// passphrase is an ASCII string. /// </param> /// <param name="saltValue"> /// Salt value used along with passphrase to generate password. Salt can /// be any string. In this example we assume that salt is an ASCII string. /// </param> /// <param name="hashAlgorithm"> /// Hash algorithm used to generate password. Allowed values are: "MD5" and /// "SHA1". SHA1 hashes are a bit slower, but more secure than MD5 hashes. /// </param> /// <param name="passwordIterations"> /// Number of iterations used to generate password. One or two iterations /// should be enough. /// </param> /// <param name="initVector"> /// Initialization vector (or IV). This value is required to encrypt the /// first block of plaintext data. For RijndaelManaged class IV must be /// exactly 16 ASCII characters long. /// </param> /// <param name="keySize"> /// Size of encryption key in bits. Allowed values are: 128, 192, and 256. /// Longer keys are more secure than shorter keys. /// </param> /// <returns> /// Encrypted value formatted as a base64-encoded string. /// </returns> public static string Encrypt(string text, string pass) { string plainText = text; string passPhrase = pass; string saltValue = "s@1tValue"; // can be any string 205
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C# string hashAlgorithm = "SHA1";// can be "MD5" int passwordIterations = 2; // can be any number string initVector = "@1B2c3D4e5F6g7H8"; // must be 16 bytes int keySize = 256; // can be 192 or 128 // Convert strings into byte arrays. // Let us assume that strings only contain ASCII codes. // If strings include Unicode characters, use Unicode, UTF7, or UTF8 // encoding. byte[] initVectorBytes = Encoding.ASCII.GetBytes(initVector); byte[] saltValueBytes = Encoding.ASCII.GetBytes(saltValue); // Convert our plaintext into a byte array. // Let us assume that plaintext contains UTF8-encoded characters. byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText); // First, we must create a password, from which the key will be derived. // This password will be generated from the specified passphrase and // salt value. The password will be created using the specified hash // algorithm. Password creation can be done in several iterations. PasswordDeriveBytes password = new PasswordDeriveBytes( passPhrase, saltValueBytes, hashAlgorithm, passwordIterations); // Use the password to generate pseudo-random bytes for the encryption // key. Specify the size of the key in bytes (instead of bits). byte[] keyBytes = password.GetBytes(keySize / 8); // Create uninitialized Rijndael encryption object. RijndaelManaged symmetricKey = new RijndaelManaged(); // It is reasonable to set encryption mode to Cipher Block Chaining // (CBC). Use default options for other symmetric key parameters. symmetricKey.Mode = CipherMode.CBC; // Generate encryptor from the existing key bytes and initialization // vector. Key size will be defined based on the number of the key // bytes. ICryptoTransform encryptor = symmetricKey.CreateEncryptor( keyBytes, initVectorBytes); // Define memory stream which will be used to hold encrypted data. MemoryStream memoryStream = new MemoryStream(); 206
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 10. ablonul de proiectare Proxy // Define cryptographic stream (always use Write mode for encryption). CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write); // Start encrypting. cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length); // Finish encrypting. cryptoStream.FlushFinalBlock(); // Convert our encrypted data from a memory stream into a byte array. byte[] cipherTextBytes = memoryStream.ToArray(); // Close both streams. memoryStream.Close(); cryptoStream.Close(); // Convert encrypted data into a base64-encoded string. string cipherText = Convert.ToBase64String(cipherTextBytes); // Return encrypted string. return cipherText; } /// <summary> /// Decrypts specified ciphertext using Rijndael symmetric key algorithm. /// </summary> /// <param name="cipherText"> /// Base64-formatted ciphertext value. /// </param> /// <param name="passPhrase"> /// Passphrase from which a pseudo-random password will be derived. The /// derived password will be used to generate the encryption key. /// Passphrase can be any string. In this example we assume that this /// passphrase is an ASCII string. /// </param> /// <param name="saltValue"> /// Salt value used along with passphrase to generate password. Salt can /// be any string. In this example we assume that salt is an ASCII string. /// </param> /// <param name="hashAlgorithm"> /// Hash algorithm used to generate password. Allowed values are: "MD5" and /// "SHA1". SHA1 hashes are a bit slower, but more secure than MD5 hashes. /// </param> /// <param name="passwordIterations"> /// Number of iterations used to generate password. One or two iterations 207
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C# /// should be enough. /// </param> /// <param name="initVector"> /// Initialization vector (or IV). This value is required to encrypt the /// first block of plaintext data. For RijndaelManaged class IV must be /// exactly 16 ASCII characters long. /// </param> /// <param name="keySize"> /// Size of encryption key in bits. Allowed values are: 128, 192, and 256. /// Longer keys are more secure than shorter keys. /// </param> /// <returns> /// Decrypted string value. /// </returns> /// <remarks> /// Most of the logic in this function is similar to the Encrypt /// logic. In order for decryption to work, all parameters of this function /// - except cipherText value - must match the corresponding parameters of /// the Encrypt function which was called to generate the /// ciphertext. /// </remarks> public static string Decrypt(string text, string pass) { string cipherText = text; string passPhrase = pass; string saltValue = "s@1tValue"; // can be any string string hashAlgorithm = "SHA1";// can be "MD5" int passwordIterations = 2; // can be any number string initVector = "@1B2c3D4e5F6g7H8"; // must be 16 bytes int keySize = 256; // can be 192 or 128 // Convert strings defining encryption key characteristics into byte // arrays. Let us assume that strings only contain ASCII codes. // If strings include Unicode characters, use Unicode, UTF7, or UTF8 // encoding. byte[] initVectorBytes = Encoding.ASCII.GetBytes(initVector); byte[] saltValueBytes = Encoding.ASCII.GetBytes(saltValue); // Convert our ciphertext into a byte array. byte[] cipherTextBytes = Convert.FromBase64String(cipherText); // First, we must create a password, from which the key will be // derived. This password will be generated from the specified // passphrase and salt value. The password will be created using // the specified hash algorithm. Password creation can be done in // several iterations.

208
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 10. ablonul de proiectare Proxy PasswordDeriveBytes password = new PasswordDeriveBytes( passPhrase, saltValueBytes, hashAlgorithm, passwordIterations); // Use the password to generate pseudo-random bytes for the encryption // key. Specify the size of the key in bytes (instead of bits). byte[] keyBytes = password.GetBytes(keySize / 8); // Create uninitialized Rijndael encryption object. RijndaelManaged symmetricKey = new RijndaelManaged(); // It is reasonable to set encryption mode to Cipher Block Chaining // (CBC). Use default options for other symmetric key parameters. symmetricKey.Mode = CipherMode.CBC; // Generate decryptor from the existing key bytes and initialization // vector. Key size will be defined based on the number of the key // bytes. ICryptoTransform decryptor = symmetricKey.CreateDecryptor( keyBytes, initVectorBytes); // Define memory stream which will be used to hold encrypted data. MemoryStream memoryStream = new MemoryStream(cipherTextBytes); // Define cryptographic stream (always use Read mode for encryption). CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read); // Since at this point we don't know what the size of decrypted data // will be, allocate the buffer long enough to hold ciphertext; // plaintext is never longer than ciphertext. byte[] plainTextBytes = new byte[cipherTextBytes.Length]; // Start decrypting. int decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length); // Close both streams. memoryStream.Close(); cryptoStream.Close();

209
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C# // Convert decrypted data into a string. // Let us assume that the original plaintext string was UTF8-encoded. string plainText = Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount); // Return decrypted string. return plainText; } /// <summary> /// Returns the hash of a string /// </summary> /// <param name="str"></param> /// <returns></returns> public static string HashString(string str) { HashAlgorithm sha = new SHA1CryptoServiceProvider(); byte[] buf = new byte[str.Length]; for (int i = 0; i < str.Length; i++) buf[i] = (byte)str[i]; byte[] result = sha.ComputeHash(buf); return Convert.ToBase64String(result); } } }

6.2. Tem pentru acas. Extindei programul astfel nct documentele i managerul de documente s poat fi pe un alt calculator iar proxy-ul s nglobeze i funcionaliti de delegare la distan. Opional, pentru eficientizarea comunicaiilor, se poate avea n vedere arhivarea documentului trimis nainte de criptare.

210
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 11

ablonul de proiectare Comand


1. Obiective 2. Scop i motivaie 3. Aplicabilitate 4. Analiza ablonului 5. Exemplu de implementare 6. Aplicaie

1. Obiective
Obiectivul principal al capitolului 11 este implementarea unui program dup ablonul de proiectare comportamental Comand (engl. Command). Se va prezenta i o metod de generare i adugare dinamic a unor controale n fereastra unui program.

2. Scop i motivaie
ablonul Comand ncapsuleaz o funcie ntr-un obiect, astfel nct este posibil trimiterea unor funcii ca parametri, formarea de cozi de apeluri, nregistrarea listei de apeluri (engl. logging) i asigurarea suportului pentru operaiile de anulare (engl. undo). S presupunem o aplicaie cu o bar de instrumente care poate fi personalizat. Cu fiecare buton al barei, utilizatorul i poate asocia funcia dorit. Deci, din punct de vedere al proiectantului, nu se poate cunoate apriori nici operaia propriu-zis care va fi efectuat de un buton i nici obiectul concret care va realiza operaia respectiv. De asemenea, pentru a avea o arhitectur elegant, toate butoanele trebuie tratate n mod unitar. Soluia propus de ablonul Comand este ncapsularea unui astfel de apel ntr-un obiect, care poate fi stocat sau trimis ca parametru altor obiecte. Dup cum se poate vedea n figura 11.1, clasa abstract Command include o operaie Execute, implementat de ctre clasele concrete derivate, care conin ca i cmp destinatarul apelului (obiectul care va realiza efectiv operaia) i care i vor transfera acestuia apelul de execuie a operaiei. Pentru simplitate, s-au omis semnturile metodelor. Trebuie subliniat faptul
211
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

c aceste clase de comand sunt clase normale, care pot include i alte cmpuri i metode pe lng metoda Execute specific ablonului.

Figura 11.1. Exemplu de sistem bazat pe ablonul Comand

n acest exemplu, destinatarii sunt clasele Document i Image. Comanda PasteCommand are un cmp de tipul Document iar clasa FlipCommand are un cmp de tipul Image. La apelul metodelor Execute, obiectele de comand apeleaz metodele corespunztoare din obiectele destinatar, dup unele eventuale prelucrri suplimentare. Clasele de comand sunt derivate dintr-o clas de baz comun i deci pot fi tratate unitar, chiar dac operaiile lor Execute au implementri diferite. ablonul permite de asemenea definirea unor comenzi macro, adic a unei mulimi de operaii. O astfel de clas, prezentat n figura 11.2, poate avea un vector de comenzi simple, pe care le apeleaz succesiv.

Figura 11.2. Comand macro


212
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 11. ablonul de proiectare Comand

Clasa MacroCommand este derivat la rndul su din aceeai clas abstract Command, deci poate fi tratat ca orice alt comand. Ea nu are ns un destinatar explicit, deoarece comenzile din serie au propriul destinatar. n msura n care sistemul dispune de mai multe comenzi, dac gestionarea acestora ar aparine exclusiv clientului, acest fapt ar conduce la creterea cuplrii ntre aceste clase. De aceea, ablonul introduce o clas suplimentar, Invoker, care este responsabil de setarea dinamic a comenzilor i de apelarea acestora. n exemplul anterior, bara de instrumente este un Invoker, care gestioneaz comenzile asociate cu butoanele sale, iar aplicaia (clasa corespunztoare ferestrei principale, de exemplu) este clientul. Odat ce o comand a fost introdus n Invoker, ea poate fi executat (o dat sau de mai multe ori), poate fi eliminat sau nlocuit n mod dinamic. Una din trsturile foarte importante care pot fi implementate uor cu ajutorul ablonului Comand este asigurarea operaiilor de anulare (engl. undo) i refacere (engl. redo) a ultimelor aciuni. n general, chiar dac aplicaia are mai multe comenzi, exist cte o singur opiune de anulare, respectiv refacere. De aceea, sistemul trebuie s cunoasc succesiunea operaiilor efectuate i modul n care starea sistemului este modificat de fiecare comand. Astfel, clasele de comand vor avea dou metode suplimentare, Undo i Redo i vor trebui s rein starea sistemului nainte de aplicarea comenzii i dup aplicarea sa (figura 11.3).

Figura 11.3. Comand cu operaii de anulare i refacere

Clasa Invoker poate reine ntr-o stiv succesiunea de comenzi efectuate iar dac se dorete de exemplu anularea ultimelor n aciuni, se va apela metoda Undo din cele n elemente scoase din stiv. Putem spune c ablonul decupleaz obiectul care invoc o operaie de cel care tie cum s o efectueze, ceea ce ofer un grad ridicat de flexibilitate n proiectarea unei aplicaii. n cazul interfeei grafice cu utilizatorul, o aplicaie poate furniza pentru o funcie att o interfa cu meniuri, ct i una cu butoane i n acest caz meniurile i butoanele vor fi
213
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

asociate cu aceleai instane ale claselor concrete de comand. Comenzile pot fi nlocuite n mod dinamic, lucru util pentru implementarea meniurilor sensibile la context. De asemenea, prin compunerea comenzilor ntr-unele de mai mari dimensiuni, se poate facilita generarea script-urilor de comand.

3. Aplicabilitate
ablonul Comand poate fi utilizat n primul rnd atunci cnd trebuie s se trimit o aciune ca parametru unui obiect, aa cum este cazul n situaia cu bara de instrumente prezentat anterior. Trimiterea poate fi fcut i prin intermediul unei funcii de apelare invers (engl. callback). De exemplu, codul de tratare a evenimentelor n platforma .NET este ncapsulat n funcii delegat i utilizat sub forma:
button.Click += new System.EventHandler(button_Click)

Comenzile reprezint un echivalent orientat obiect pentru funciile de apelare invers. S presupunem c ntr-un sistem de echilibrarea ncrcrii, activitile de calcul (task-urile) trebuie transferate pe diferite maini. Fiecare activitate de calcul este diferit. Pentru a trata n mod unitar toate aceste activiti, ele pot fi ncapsulate n obiecte de comand. La fel, dac activitile sunt preluate pentru rulare de fire de execuie dintr-un bazin (engl. thread pool), utilizarea comenzilor simplific foarte mult procesul, deoarece un fir de execuie nu trebuie s tie dect c o activitate are o metod Execute care trebuie apelat. Dup cum am menionat, o comand poate avea posibilitatea anulrii sau refacerii aciunii. Dac sistemul trebuie s permit anularea i refacerea unei ntregi succesiuni de comenzi, acest fapt poate fi uor implementat prin introducerea n Invoker a unor liste (sau stive) de comenzi pentru anulare, respectiv refacere. n momentul cnd se anuleaz o operaie, comanda respectiv se scoate din lista comenzilor de anulare i se introduce n lista comenzilor de refacere. Se procedeaz analog n cazul apelrii unei operaii de refacere. Prin traversarea acestor liste se pot asigura oricte niveluri de anulare i refacere. Pentru sisteme care gestioneaz date foarte complexe, salvarea strii n cazul blocrii se poate face tot cu ajutorul comenzilor. n aceast situaie nu este fezabil salvarea datelor dup fiecare operaie efectuat. Aplicaia
214
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 11. ablonul de proiectare Comand

poate s pstreze o nregistrare (engl. log) cu seria de comenzi efectuate de la pornirea sa. Dac la un moment dat sistemul se blocheaz, starea sa poate fi refcut din cea iniial, aplicnd n ordine comenzile salvate pe harddisk. n interfaa obiectelor de comand pot fi adugate operaii de ncrcare i salvare. Salvarea comenzilor poate fi att o list cu identificatorii i parametrii acestora, ct i serializarea efectiv a obiectelor de comand aplicate.

4. Analiza ablonului
Diagrama generic de clase a ablonului Comand este prezentat n figura 11.4.

Figura 11.4. Diagrama de clase a ablonului Comand

Clasa abstract (sau interfaa) Command declar metode precum Execute, eventual Undo i Redo. Clasele concrete ConcreteCommand implementeaz operaia Execute prin invocarea operaiei sau operaiilor corespunztoare din obiectul Receiver. Clasa Receiver tie cum s efectueze operaiile asociate cu executarea unei comenzi. Orice clas poate servi drept destinatar. Clasa Invoker cere comenzii s execute aciunea. Clientul creeaz un obiect ConcreteCommand i i stabilete destinatarul. Modul n care acioneaz participanii este detaliat n diagrama de secvene din figura 11.5.

215
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

Figure 11.5. Diagrama de secvene a ablonului Comand

Clientul creeaz obiectul ConcreteCommand i i precizeaz destinatarul. Obiectul Invoker stocheaz obiectul ConcreteCommand. Cnd este nevoie, obiectul Invoker apeleaz operaia Execute din obiectul Command. n cazul n care comenzile pot fi anulate, obiectul ConcreteCommand i stocheaz starea pentru anularea comenzii nainte de a aplica operaia Execute. Obiectul ConcreteCommand apeleaz operaiile din obiectul Receiver pentru a ndeplini aciunea propriu-zis. Consecina principal a ablonului este decuplarea obiectului care invoc o operaie de obiectul care tie cum s o efectueze. Astfel, noi comenzi pot fi adugate foarte uor deoarece nu sunt necesare modificri ale claselor existente.

5. Exemplu de implementare
Codul C# corespunztor structurii ablonului Comand este prezentat n cele ce urmeaz. Comanda abstract
abstract class Command { protected Receiver _receiver; public Command(Receiver receiver) { _receiver = receiver; } 216
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 11. ablonul de proiectare Comand abstract public void Execute(); }

Comanda concret
class ConcreteCommand : Command { public ConcreteCommand(Receiver receiver) : base(receiver) { } public override void Execute() { _receiver.Action(); } }

Destinatarul
class Receiver { public void Action() { Console.WriteLine("Apelul metodei din destinatar"); } }

Invocatorul
class Invoker { private Command _command; public void SetCommand(Command command) { _command = command; } public void ExecuteCommand() { _command.Execute(); } }

217
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

Clientul
public class Client { public static void Main(string[] args) { // Se creeaz destinatarul, comanda i invocatorul Receiver r = new Receiver(); Command c = new ConcreteCommand(r); Invoker i = new Invoker(); // Se seteaz i se execut comanda i.SetCommand(c); i.ExecuteCommand(); } }

6. Aplicaii
6.1. Realizai un program care simuleaz o foaie de calcul (gen Microsoft Excel). Un schelet al aplicaiei pentru construirea interfeei grafice cu utilizatorul (prezentat n figura 11.6) este inclus dup observaii i recomandri.

Figura 11.6. Exemplu de rezolvare: interfaa cu utilizatorul

218
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 11. ablonul de proiectare Comand

Observaii: Controlul de tip grid este realizat dinamic cu text-box-uri. Alternativ, se poate lucra cu un control DataGridView; Componentele controlului sunt de fapt de tip ExtendedTextBox, clas derivat din TextBox, care include o metod de formatare special a numerelor din foaia de calcul: cu dou zecimale i aliniate la dreapta. Atunci cnd se editeaz textul unui ExtendedTextBox, n momentul n care se apas ENTER sau se prsete controlul respectiv, deci cnd se trimite comanda, Text-ul este deja modificat. Pentru a pstra ntr-un mod mai convenabil starea anterioar, se poate folosi proprietatea PreviousText. Cum ar putea fi proiectat comanda de modificare a textului unei celule pentru a nu fi nevoii s folosii aceast proprietate? Rmne la latitudinea proiectantului s stabileasc gradul de complexitate al comenzilor dac o comand acioneaz asupra unui TextBoxGrid sau asupra unui ExtendedTextBox. De obicei, se recomand utilizarea unor comenzi ct mai simple. Recomandri: Se poate lucra cu trei clase de comenzi, pentru schimbarea textului, schimbarea formatului i schimbarea culorii unui ExtendedTextBox; Comanda va primi n constructor o referin la ExtendedTextBox-ul asupra cruia se fac modificrile (acesta este Receiver-ul).

Pentru a v putea concentra exclusiv asupra aplicrii ablonului, n continuare se dau cteva clase ce urmeaz a fi completate sau utilizate n program. MainForm.cs
namespace Spreadsheet { public partial class MainForm : Form { public MainForm() { InitializeComponent();

219
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C# _grid = new TextBoxGrid(Controls, 25, 120, new KeyEventHandler(textBox_KeyDown), new EventHandler(textBox_Leave)); _invoker = new Invoker(_grid); } TextBoxGrid _grid; Invoker _invoker; int _selected; private void textBox_KeyDown(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Enter) { // cnd se apas ENTER ntr-o celul ExtendedTextBox tb = (ExtendedTextBox)sender; string name = tb.Name; _selected = Convert.ToInt32(name.Substring(2)); this.ActiveControl = _grid.GetSuccessor(_selected); } } private void textBox_Leave(object sender, EventArgs e) { // cnd o celul nu mai este controlul selectat activ din fereastr Control ac = this.ActiveControl; ExtendedTextBox tb = (ExtendedTextBox)sender; string name = tb.Name; _selected = Convert.ToInt32(name.Substring(2)); tb.FormatText(); // de completat - tratarea schimbrii textului this.ActiveControl = ac; UpdateUndoRedoCombos(); } private void buttonColor_Click(object sender, EventArgs e) { if (colorDialog1.ShowDialog() != DialogResult.OK) return;

220
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 11. ablonul de proiectare Comand Color c = colorDialog1.Color; buttonColor.ForeColor = c; //buttonColor.BackColor = Color.FromArgb(255 - c.R, 255 - c.G, 255 - c.B); // de completat UpdateUndoRedoCombos(); } private void buttonNormal_Click(object sender, EventArgs e) { // de completat UpdateUndoRedoCombos(); } private void buttonBold_Click(object sender, EventArgs e) { // de completat UpdateUndoRedoCombos(); } private void buttonItalic_Click(object sender, EventArgs e) { // de completat UpdateUndoRedoCombos(); } private void UpdateUndoRedoCombos() { comboBoxUndo.Items.Clear(); string[] str = _invoker.UndoNames.ToArray(); for (int i = 0; i < str.Length; i++) comboBoxUndo.Items.Add(str[i]); if (comboBoxUndo.Items.Count > 0) { comboBoxUndo.SelectedIndex = 0; buttonUndo.Enabled = true; } else buttonUndo.Enabled = false; comboBoxRedo.Items.Clear(); str = _invoker.RedoNames.ToArray(); for (int i = 0; i < str.Length; i++) comboBoxRedo.Items.Add(str[i]);

221
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C# if (comboBoxRedo.Items.Count > 0) { comboBoxRedo.SelectedIndex = 0; buttonRedo.Enabled = true; } else buttonRedo.Enabled = false; } private void buttonUndo_Click(object sender, EventArgs e) { _invoker.Undo(); UpdateUndoRedoCombos(); } private void buttonRedo_Click(object sender, EventArgs e) { _invoker.Redo(); UpdateUndoRedoCombos(); } private void buttonExit_Click(object sender, EventArgs e) { Close(); } } }

ExtendedTextBox.cs
namespace Spreadsheet { class ExtendedTextBox : TextBox { private string _previousText; public string PreviousText { get { return _previousText; } set { _previousText = value; } }

222
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 11. ablonul de proiectare Comand public ExtendedTextBox() : base() { _previousText = ""; } public void FormatText() { double d; if (double.TryParse(Text, out d)) { Text = d.ToString("F2"); TextAlign = HorizontalAlignment.Right; } else TextAlign = HorizontalAlignment.Left; } } }

TextBoxGrid.cs
namespace Spreadsheet { class TextBoxGrid { private ExtendedTextBox[] _textBoxes; public const int Size = 5; public TextBoxGrid(Control.ControlCollection controlCollection, int left, int top, KeyEventHandler keyDownEvent, EventHandler leaveEvent) { _textBoxes = new ExtendedTextBox[Size * Size]; for (int i = 0; i < Size * Size; i++) { int x = i % Size; int y = i / Size; _textBoxes[i] = new ExtendedTextBox(); _textBoxes[i].Width = 100; _textBoxes[i].Height = 20; _textBoxes[i].Left = left + x * 100; _textBoxes[i].Top = top + y * 20; _textBoxes[i].Text = ""; _textBoxes[i].Name = "Tb" + i; 223
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C# _textBoxes[i].KeyDown += keyDownEvent; _textBoxes[i].Leave += leaveEvent; controlCollection.Add(_textBoxes[i]); } for (int i = 0; i < Size * Size; i++) _textBoxes[i].PreviousText = _textBoxes[i].Text; Label[] labelsX = new Label[Size]; for (int i = 0; i < Size; i++) { labelsX[i] = new Label(); labelsX[i].Text = ((char)(i + 'A')).ToString(); labelsX[i].Left = left + i * 100 + 48; labelsX[i].Top = top - 15; controlCollection.Add(labelsX[i]); } Label[] labelsY = new Label[Size]; for (int i = 0; i < Size; i++) { labelsY[i] = new Label(); labelsY[i].Text = (i + 1).ToString(); labelsY[i].Left = left - 15; labelsY[i].Height = 20; labelsY[i].Top = top + i * 20 + 4; controlCollection.Add(labelsY[i]); } } public void Clear() { for (int i = 0; i < Size * Size; i++) { _textBoxes[i].Clear(); _textBoxes[i].Font = new Font(_textBoxes[i].Font, FontStyle.Regular); _textBoxes[i].ForeColor = Color.Black; _textBoxes[i].PreviousText = _textBoxes[i].Text; } } public ExtendedTextBox GetSuccessor(int cellNumber) { cellNumber = (cellNumber + 1) % (Size*Size); return _textBoxes[cellNumber]; }

224
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 11. ablonul de proiectare Comand public string GetCoords(int cellNumber) { char tbx = (char)((cellNumber % Size) + 'A'); int tby = cellNumber / Size + 1; return tbx.ToString() + tby; } public ExtendedTextBox GetCell(int cellNumber) { return _textBoxes[cellNumber]; } } }

ICommand.cs
namespace Spreadsheet { interface ICommand { bool Execute(); void Undo(); void Redo(); } }

Invoker.cs
namespace Spreadsheet { class Invoker { private TextBoxGrid _grid; private Stack<ICommand> _commands; private Stack<ICommand> _redoCommands; private Stack<string> _undoNames, _redoNames; public Stack<string> RedoNames { get { return _redoNames; } }

225
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C# public Stack<string> UndoNames { get { return _undoNames; } } public Invoker(TextBoxGrid grid) { _grid = grid; _commands = new Stack<ICommand>(); _redoCommands = new Stack<ICommand>(); _undoNames = new Stack<string>(); _redoNames = new Stack<string>(); } public void SetAndExecute(ICommand command, string description) { // de completat } public void Undo() // (int level) { // este foarte simpl anularea mai multor niveluri de aciuni: // a ultimelor "level" comenzi // de completat } public void Redo() // (int level) { // de completat } } }

ChangeColorCommand.cs
namespace Spreadsheet { class ChangeColorCommand : ICommand { ExtendedTextBox _textBox; // alte cmpuri

226
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 11. ablonul de proiectare Comand public ChangeColorCommand(ExtendedTextBox textBox, Color color) { //... } public bool Execute() { //... // returneaz true dac se modific ceva n _textBox // returneaz false dac nu se modific nimic return false; } public void Undo() { //... } public void Redo() { //... } } }

ChangeFormatCommand.cs
namespace Spreadsheet { class ChangeFormatCommand : ICommand { ExtendedTextBox _textBox; // alte cmpuri public ChangeFormatCommand(ExtendedTextBox textBox, FontStyle format) { //... } public bool Execute() { //... // exemplu de schimbare a corpului de liter: // _textBox.Font = new Font(_textBox.Font, _newStyle); // returneaz true dac se modific ceva n _textBox 227
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C# // returneaz false dac nu se modific nimic return false; } public void Undo() { //... } public void Redo() { //... } } }

ChangeTextCommand.cs
namespace Spreadsheet { class ChangeTextCommand : ICommand { ExtendedTextBox _textBox; // alte cmpuri public ChangeTextCommand(ExtendedTextBox textBox) { //... } public bool Execute() { // textul nou deja exist n _textBox.Text //... // returneaz true dac se modific ceva n _textBox // returneaz false dac nu se modific nimic return false; } public void Undo() { //... }

228
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 11. ablonul de proiectare Comand public void Redo() { //... } } }

6.2. Tem pentru acas. Extindei programul astfel nct s permit operaii simple cu numerele din celule (figura 11.7).

Figura 11.7. Exemplu de rezolvare: adugarea unor operaii matematice simple

La apsarea tastei ENTER n celula D1, coninutul su va deveni 5.00. Operaii permise vor fi: Add (adunare), Sub (scdere), Mul (nmulire), Div (mprire), cu exact 2 parametri. Se va afia un mesaj de eroare dac celulele trimise ca argumente nu conin numere valide. Cnd cursorul revine n celula D1, deci cnd rencepe editarea celulei, va aprea din nou formula. Rezultatul operaiei apare numai cnd celula nu este selectat. Se vor pstra operaiile de anulare (undo) i refacere (redo).

229
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

230
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 12

Evaluarea vitezei de execuie a unui program


1. Obiective 2. Metoda DateTime 3. Pointeri n C# 4. Metoda PerformanceCounter 5. Metoda Stopwatch 6. Compilarea JIT 7. Aplicaii

1. Obiective
Cnd dorim s evalum performanele unei aplicaii software, de cele mai multe ori ncercm s-i determinm viteza de execuie. Exist diverse strategii pentru determinarea acesteia, fie direct, prin msurarea ct mai precis a intervalului de timp dintre pornirea programului (sau a unei funcii care ne intereseaz) i oprirea sa, fie indirect, prin evaluarea numrului de instruciuni i a naturii acestora, abordare ntlnit mai ales n studiile teoretice de determinare a complexitii. n acest capitol, vom descrie trei metode de msurare direct a vitezei de execuie a unui program.

2. Metoda DateTime
Prima metod utilizeaz clasa DateTime. Proprietatea DateTime.Now.Ticks numr intervalele de (teoretic!) 100 de nanosecunde scurse de la ora 0 a datei de 1 ianuarie, anul 1. Pentru msurarea timpului dintre dou momente, se preia aceast valoare la cele dou momente i se face diferena. De exemplu, la pornirea unei funcii, respectiv dup terminarea execuiei sale:
long startTicks = DateTime.Now.Ticks; ApelFunctie(); double dif = (DateTime.Now.Ticks - startTicks) / 10000.0; // dif este calculat n milisecunde

231
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

Avantajul acestei metode este simplitatea sa din punctul de vedere al programatorului. Practic, metoda se poate folosi pentru intervale de timp mai mari, de peste 1 ms.

3. Pointeri n C#
De multe ori, funciile scrise n C sau C++ primesc pointeri ca parametri. Dei n C# nu este uzual lucrul cu pointeri, acest limbaj (spre deosebire de Java) l permite n cadrul unor construcii speciale. De exemplu, ntr-un DLL poate exista o funcie cu urmtorul prototip:
int NumarDivizori (int *n);

Importarea acestei funcii se va face astfel:


[DllImport("Divizibilitate", EntryPoint="NumarDivizori")] private static unsafe extern int DllNumarDivizori(int* n); public static unsafe int NumarDivizori(int n) { int arg = n, rez = 0; // adresa argumentului este "fixat" n memorie, deoarece managementul automat // al memoriei presupune "mutarea" diferitelor zone de memorie n vederea optimizrii fixed (int *pArg = &arg) { // apelul se face cu adresa argumentului arg rez = DllNumarDivizori(pArg); } return rez; }

Pentru compilarea codului unsafe, trebuie prevzut aceast opiune n proprietile proiectului din Solution Explorer.

232
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 12. Evaluarea vitezei de execuie a unui program

Figura 12.1. Opiunea pentru compilarea codului unsafe

S considerm acum cazul n care funcia C returneaz un pointer. De exemplu, o funcie pentru concatenarea a dou iruri de caractere:
extern "C" __declspec(dllexport) char* MyAppend(char* first, char* second) { char *result = new char[strlen(first) + strlen(second)]; strcpy(result, first); strcat(result, second); return result; }

Importarea acestei funcii se va face n felul urmtor:


[DllImport("StringDll", EntryPoint = "MyAppend")] public static extern unsafe IntPtr StringAppend( [MarshalAs(UnmanagedType.LPStr)] string arg1, [MarshalAs(UnmanagedType.LPStr)] string arg2 );

Directiva MarshalAs stabilete modul de interpretare a argumentelor i a tipurilor de return la interfaa dintre memoria gestionat de mediul .NET
233
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

(managed) i cea negestionat (unmanaged). Interpretarea se face n momentul execuiei programului. n exemplul de mai sus, funcia C primete un pointer la ir de caractere, care este convertit automat din tipul C# string la apel. Funcia ntoarce de asemenea un pointer: IntPtr. Pentru convertirea rezultatului napoi la string n C#, se pot folosi instruciuni de tipul:
IntPtr target = StringAppend(str1, str2); string s = Marshal.PtrToStringAnsi(target);

Pentru a putea importa o funcie cu DllImport, trebuie inclus namespace-ul System.Runtime.InteropServices.

4. Metoda PerformanceCounter
Pentru intervale mai precise, se poate folosi o alt metod care presupune apelarea direct a funciilor Windows de lucru cu numrtorul calculatorului:
[DllImport("kernel32", EntryPoint = "QueryPerformanceFrequency")] private static unsafe extern bool QueryPerformanceFrequency(Int64* f); [DllImport("kernel32", EntryPoint = "QueryPerformanceCounter")] private static unsafe extern bool QueryPerformanceCounter(Int64* c); static Int64 _t1, _t2, _htrFrecv; static bool _htrInit; static PerformanceCounterSpeed() { // iniializarea numrtorului - o singur dat nainte de utilizarea clasei InitCounter(); } private static unsafe bool InitCounter() { _t1 = 0; _t2 = 0; _htrFrecv = 0; _htrInit = false; fixed (Int64* frecv = &_htrFrecv) { _htrInit = QueryPerformanceFrequency(frecv); } return _htrInit; }

234
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 12. Evaluarea vitezei de execuie a unui program public unsafe void BeginTest() { fixed (Int64* t1 = &_t1) { QueryPerformanceCounter(t1); } } /// <summary> /// Returneaz diferena n milisecunde /// </summary> /// <returns></returns> public unsafe double EndTest() { fixed (Int64* t2 = &_t2) { QueryPerformanceCounter(t2); } Int64 difCounts = _t2 - _t1; double difSeconds = (double)difCounts / (double)_htrFrecv; return difSeconds * 1000.0; }

4.1. Metode de accelerare


O metod mai simpl de a apela funciile de mai sus din kernel32 este folosind tipul long n loc de Int64*. Programul poate fi accelerat prin eliminarea verificrilor de securitate la apelul funciilor unmanaged, cu ajutorul atributului SuppressUnmanagedCodeSecurity:
[System.Security.SuppressUnmanagedCodeSecurity()] private static extern bool QueryPerformanceCounter(out long lpPerformanceCount);

Cnd din cod managed se apeleaz funcii unmanaged, se realizeaz verificarea permisiunilor de securitate pentru a stabili dac apelantul are drepturile necesare pentru a face apelul. Prin aplicarea explicit a acestui atribut, se elimin aceste verificri, ceea ce crete viteza de execuie. De asemenea, un program compilat n mod Release este n general mai rapid dect acelai cod compilat n mod Debug.

235
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

5. Metoda Stopwatch
O metod care combin simplitatea apelurilor oferit de clasa DateTime cu precizia funciilor PerformanceCounter este utilizarea clasei Stopwatch din namespace-ul System.Diagnostics. Msurarea timpului de execuie se realizeaz astfel:
long startTicks = Stopwatch.GetTimestamp(); ApelFunctie(); double dif = (Stopwatch.GetTimestamp() - _startTicks) * 1000.0 / Stopwatch.Frequency; // dif este calculat n milisecunde

Indiferent de metoda de msurare aleas, se recomand efectuarea mai multor experimente pentru aceeai funcie i apoi calcularea statistic a valorii medii i deviaiei standard.

6. Compilarea JIT
n mod tradiional, exist dou modaliti principale de execuie a codului surs pe un procesor: interpretarea i compilarea. Codul interpretat este transformat n cod main n mod continuu la fiecare executare. Codul compilat static este transformat n cod main o singur dat, naintea execuiei. Interpretarea necesit mai puine resurse, ns timpul de execuie este mai mare din cauza stratului software suplimentar care prelucreaz instruciunile. Un limbaj interpretat permite unele lucruri imposibile ntr-un limbaj compilat, de exemplu adugarea sau modificarea unor funcii chiar n timpul execuiei. De obicei dezvoltarea aplicaiilor ntr-un limbaj interpretat este mai simpl deoarece nu este necesar compilarea ntregului program cnd se dorete testarea numai a unor seciuni mici de cod. Ca exemple de limbaje interpretate putem aminti versiunile iniiale de Perl, Ruby sau Matlab. Compilatoare exist pentru majoritatea limbajelor de programare importante, precum C, C++, Pascal etc. Dup cum am amintit i n capitolul 1, seciunea 3.1, compilarea la timp (engl. just-in-time compilation, JIT) reprezint o abordare hibrid, n care transformarea n cod main are loc continuu, ca n cazul interpretoarelor, ns codul transformat este stocat (engl. cached) pentru a nu afecta viteza de execuie a programului. Unitatea de compilare este metoda. Unitile sunt compilate n cod nativ doar nainte de prima utilizare.
236
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 12. Evaluarea vitezei de execuie a unui program

Pe platforma .NET, toate limbajele folosesc Common Language Runtime, CLR, maina virtual responsabil pentru gestionarea execuiei programelor. CLR compileaz codul intermediar CIL n instruciuni main executate de procesorul calculatorului. CLR mai asigur servicii suplimentare cum ar fi managementul memoriei, sigurana tipurilor (engl. type safety) i tratarea excepiilor. Indiferent de limbajul de programare, toate programele scrise pentru platforma .NET sunt executate de ctre CLR. ntruct optimizrile de baz sunt realizate n timpul compilrii codului surs, compilarea din CIL n cod main este mult mai rapid. Compilatorul JIT produce cod nativ puternic optimizat pe baza datelor despre mediul de execuie, proces numit profiling. Acesta reprezint capacitatea de a msura viteza de execuie a prilor unei aplicaii sau a ntregii aplicaii, astfel nct s fie descoperite zonele care provoac ntrzieri. De exemplu, se poate descoperi care metode sunt utilizate frecvent i acestea pot fi transformate n cod inline. Dei chiar i aceste optimizri consum un timp suplimentar, viteza de execuie crete la apelurile ulterioare. Compilatorul JIT cauzeaz o mic ntrziere la prima execuie a unei aplicaii, din cauza timpului necesar pentru ncrcarea i compilarea codului intermediar. n general, cu ct mai multe optimizri realizeaz JIT, cu att mai bun este codul generat, ns crete i ntrzierea iniial. Un compilator JIT trebuie s realizeze deci un compromis ntre calitatea codului generat i timpul necesar pentru compilare. Utilitarul Native Image Generator, Ngen, poate fi o soluie pentru reducerea ntrzierii iniiale. Ngen precompileaz codul intermediar n cod main nativ i de aceea nu mai este necesar compilarea n momentul execuiei. Platforma .NET 2.0 precompileaz toate bibliotecile DLL dup instalare. Precompilarea asigur o modalitate de a mbunti timpul de pornire a aplicaiilor, ns calitatea codului compilat poate fi inferioar compilrii JIT, aa cum i codul compilat static, fr optimizri ghidate de profil, este inferioar codului compilat la timp. Precompilarea unui assembly se poate realiza cu o comand de tipul:
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\ngen.exe install nume-assembly

Calea ctre utilitar poate fi diferit, n funcie de versiunea platformei .NET utilizate. Imaginea precompilat a unui assembly poate fi ndeprtat din cache folosindu-se opiunea uninstall. Figura 12.2 prezint comportamentul aceluiai program (un exemplu de rezolvare pentru aplicaia 7.1), care msoar viteza de execuie a unor funcii. n stnga, pentru versiunea compilat JIT, se observ c execuia
237
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

iniial a funciilor dureaz mai mult dect apelurile ulterioare. n dreapta, pentru versiunea precompilat cu Ngen, se observ c toate apelurile au un timp relativ egal de execuie.

Figura 12.2. Viteza de execuie a unor funcii n variantele: a) compilate JIT; b) precompilate

n cazul general ns, nu se poate garanta c un cod precompilat cu Ngen va avea performane superioare fa de versiunea compilat la timp. Exist i metode mai complicate de a precompila assembly-urile prin program, ns acestea nu fac obiectul prezentului capitol.

7. Aplicaii
7.1. Evaluai viteza de execuie a urmtorilor algoritmi de sortare, pentru vectori de numere reale de diferite dimensiuni: Quick sort, Shell sort i Bubble sort. Se va crea cte o clas pentru fiecare din cele trei metode, care s implementeze o interfa comun:

238
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 12. Evaluarea vitezei de execuie a unui program void BeginTest(); double EndTest(); // returneaz diferena

Un exemplu de rezolvare, cu dou variante de execuie, este prezentat n figura 12.3.

Figura 12.3. Exemplu de rezolvare: interfaa cu utilizatorul

n continuare, se prezint un schelet al clasei care implementeaz algoritmii de sortare considerai.


namespace Speed { public class Sorting { public static void QuickSort(double[] vector) { DoQuickSort(vector, 0, vector.Length - 1); } private static void DoQuickSort(double[] vector, int low, int high) { if (high > low) { int k = Partition(vector, low, high); // procedura de partiionare 239
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C# DoQuickSort(vector, low, k - 1); DoQuickSort(vector, k + 1, high); } } private static int Partition(double[] vector, int low, int high) { int l = low; int h = high; double x = vector[l]; double temp; while (l < h) { while ((vector[l] <= x) && (l < high)) l++; while ((vector[h] > x) && (h >= low)) h--; if (l < h) { temp = vector[l]; vector[l] = vector[h]; vector[h] = temp; } } temp = vector[h]; vector[h] = vector[low]; vector[low] = temp; return h; } public static void ShellSort(double[] vector) { for (int dist = vector.Length / 2; dist > 0; dist /= 2) for (int i = dist; i < vector.Length; i++) for (int j = i - dist; j >= 0 && vector[j] > vector[j + dist]; j -= dist) { double aux = vector[j]; vector[j] = vector[j + dist]; vector[j + dist] = aux; } }

240
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 12. Evaluarea vitezei de execuie a unui program public static void BubbleSort(double[] vector) { 2 // de completat cu varianta neoptimizat O(n ) } } }

Observaii: Pentru a le putea compara performanele, trebuie s ne asigurm c toi algoritmii sunt aplicai aceluiai vector. n cazul vectorilor generai aleatoriu, utili pentru studierea complexitii medii, exist dou variante: o S se memoreze un vector, care s fie copiat de fiecare dat nainte de aplicarea unui algoritm; o S se genereze pentru fiecare algoritm acelai vector de numere aleatorii. n C#, generarea unui numr aleatoriu se face cu ajutorul unui obiect de tip Random. Acesta este de fapt un generator de numere pseudoaleatorii, n care numrul urmtor este generat pe baza numrului anterior, aplicnd un algoritm specific. Dac se pleac de fiecare dat de la acelai numr, se va genera de fiecare dat acelai ir. n acest scop se poate trimite ca parametru n constructor un numr seed, care ajut la iniializarea generatorului. Dac acest parametru lipsete (constructorul vid), se utilizeaz implicit timpul curent, care este de fiecare dat diferit i deci i irul de numere generat va fi de asemenea diferit. Aceast metod este mai eficient deoarece elimin consumul suplimentar de memorie necesar pentru pstrarea vectorului; Pentru timpi de execuie mici, este normal ca metoda DateTime s returneze valoarea 0; Nu este obligatorie afiarea grafic a comparaiei ntre timpii de execuie ai algoritmilor; O metod util de sortare n C# este Array.Sort, care garanteaz complexitatea .

7.2. Tem pentru acas. Extindei programul prin adugarea unui alt algoritm de sortare (la alegere) i afiai grafic comparativ timpii de execuie ai algoritmilor.

241
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

242
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 13

Testarea unitilor cu NUnit


1. Obiectiv 2. Testarea unitilor 3. Utilizarea platformei NUnit 4. Aplicaii

1. Obiectiv
n capitolul 13, vom descrie o metod de testare a unitilor folosind platforma dedicat NUnit.

2. Testarea unitilor
Testarea unitilor este o metod de a verifica funcionalitatea corect a unitilor individuale de cod surs. O unitate este cea mai mic parte testabil dintr-o aplicaie. Scopul testrii unitilor este de a izola fiecare parte a unui program i de a arta c prile individuale sunt corecte. Testarea unei uniti furnizeaz un contract scris i strict pe care codul respectiv trebuie s l satisfac. Astfel, testarea unitilor ajut la descoperirea din timp a problemelor n ciclul de dezvoltare. Testarea unitilor permite programatorului s refactorizeze codul mai trziu, i asigur n continuare funcionalitatea corect. De exemplu, testarea de regresiune presupune ca atunci cnd un defect este descoperit i corectat, se nregistreaz i un test care expune defectul, astfel nct acesta s poat fi retestat dup schimbrile ulterioare ale programului. n mod normal sunt scrise teste pentru toate metodele astfel nct atunci cnd o modificare provoac un defect, acesta s poat fi uor identificat i reparat. Testarea unitilor ajut la eliminarea incertitudinii privind codul i poate fi folosit ntr-o abordare de testare bottom-up. Prin testarea mai nti a prilor unui program i apoi a sumei prilor, testarea de integrare devine mult mai uoar. Testarea unitilor asigur un fel de documentaie vie a sistemului. Dezvoltatorii care vor s afle funcionalitile oferite de o unitate i cum este ea folosit i pot studia testele pentru a avea o nelegere de baz asupra
243
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

API-ului su. Cazurile de test pot indica folosirea potrivit sau nepotrivit a unitii. Documentaia narativ clasic este mai predispus la apariia diferenelor fa de implementare i deci poate deveni mai uor depit. Testarea este o activitate distinct de depanare (engl. debugging), dei graniele celor dou nu sunt stricte. Testarea este procesul metodic de a demonstra existena defectelor din program. Depanarea este activitatea de descoperire a cauzelor defectelor. Testarea conduce la depanare, care conduce la reparare, care conduce la re-testare pentru a demonstra c repararea a fost corect.

3. Utilizarea platformei NUnit


NUnit este o platform open source pentru testarea unitilor pentru aplicaii .NET. Are acelai scop ca i JUnit pentru aplicaii Java. Pentru a descrie modul de lucru cu NUnit, s considerm o clas pentru efectuarea unor operaii artimetice elementare:
public class MathOps { public static double Add(double x, double y) { return x + y; } public static double Sub(double x, double y) { return x - y - 1; // rezultat incorect } public static double Mul(double x, double y) { return x * y + 0.5; // rezultat incorect } public static double Div(double x, double y) { if (x == 0 && y == 0) throw new Exception("Undefined operation."); // if (y == 0) // throw new Exception("Division by zero."); // lipsete excepia return x / y; } 244
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 13. Testarea unitilor cu NUnit public static double Pow(double x, double y) { throw new Exception("The method or operation is not implemented."); } }

Pentru a utiliza platforma NUnit, trebuie adugat mai nti o referin la assembly-ul nunit.framework.dll aflat n directorul NUnit 2.4.8\bin\. Pentru versiunile ulterioare este de presupus c numele acestuia se va modifica n mod corespunztor. Pentru fiecare clas testat, se recomand crearea unei alte clase de test. n aceste fiiere trebuie inclus namespace-ului NUnit.Framework. Pentru a indica faptul c o clas este destinat testrii cu NUnit, se folosete atributul [TestFixture]. Important! Clasele marcate [TestFixture] trebuie s fie publice.
[TestFixture] public class OperatiiTest { ... }

n aceast clas vom include metodele de testare. Aceste metode trebuie s fie obligatoriu fr parametri i s aib tipul de return void. O astfel de metod este marcat cu atributul [Test]. De exemplu:
[Test] public void Addition() { Assert.AreEqual(3, MathOps.Add(1, 2)); }

Cea mai des utilizat modalitate de testare este cu clasa Assert. n metoda AreEqual primul parametru reprezint valoarea ateptat iar al doilea rezultatul operaiei testate. n legtur cu operaiile Assert trebuie fcute cteva precizri: Aseriunile nu nlocuiesc excepiile. Excepiile se refer la necesitile codului, aseriunile se refer la presupunerile codului;

245
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

O aseriune ne poate spune nu numai ce s-a ntmplat i unde (ca o excepie), ci i de ce; Aseriunile pot fi considerate i o form de documentaie, comunicnd celorlali dezvoltatori ce presupuneri s-au fcut n implementare, presupuneri de care depinde corecta funcionare a programului.

Cnd o aseriune este adevrat, nseamn c totul se desfoar aa cum era prevzut. Cnd este fals, nseamn c a aprut o eroare neateptat n cod. De exemplu, dac un programator presupune c ntr-un fiier nu vor exista niciodat mai mult de 50000 de linii, se poate pune o aseriune cu privire la numrul de linii din fiierul citit. Dac programul ntlnete un fiier mai mare, presupunerea a fost greit i programatorul trebuie avertizat. Aceste metode sunt utile deci pentru depistarea erorilor semantice, aa cum compilatorul semnaleaz erorile sintactice. Aseriunile trebuie s indice erorile programatorului, nu ale utilizatorului.
[Test] public void Subtraction() { Assert.AreEqual(-1, MathOps.Sub(1, 2)); } [Test] public void Multiplication() { Assert.AreEqual(12, MathOps.Mul(3, 4)); } [Test] public void Division() { Assert.AreEqual(2.0 / 3.0, MathOps.Div(2, 3)); }

n cazul operaiei de mprire, pot fi aruncate excepii dac argumentele sunt invalide. n cazul testrii, dac argumentele sunt invalide, ne ateptm ca apelul s determine aruncarea unei excepii. Programul testat are un defect dac nu se arunc excepia. n NUnit, aceast situaie este tratat cu ajutorul atributului [ExpectedException()], care primete ca parametru tipul de excepie ateptat. n cazul nostru, avem doar excepii de
246
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 13. Testarea unitilor cu NUnit

tipul de baz Exception. Dac am crea clase particulare de excepie pentru fiecare situaie, am putea testa c i tipul de excepie aruncat este cel corect.
[Test] [ExpectedException(typeof(Exception))] public void DivisionExc1() { MathOps.Div(0, 0); } [Test] [ExpectedException(typeof(Exception))] public void DivisionExc2() { MathOps.Div(5, 0); }

Cnd unele metode din programul testat nu sunt nc implementate, ceea ce ar determina oricum picarea testului, se poate marca o metod de test cu atributul [Ignore], care primete ca parametru un mesaj de atenionare. n cazul nostru, operaia Pow nu este nc implementat. Testul poate fi ns scris de la nceput i cnd operaia va fi implementat se va elimina doar atributul de ignorare din metoda de test.
[Test] [Ignore("Operatia nu este inca implementata")] public void Power() { Assert.AreEqual(8, MathOps.Pow(2, 3)); }

n continuare, se compileaz programul i se deschide interfaa vizual a platformei NUnit: aplicaia nunit.exe din acelai director NUnit 2.4.8\bin\. Se creeaz eventual un nou proiect i se adaug assembly-ul care trebuie testat din meniul Project Add Assembly... (de exemplu Operatii.exe). Apoi se apas butonul Run (figura 13.1).

247
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

Figura 13.1. Platforma NUnit: interfaa grafic

Pentru fiecare metod care se testeaz se pot obine informaii suplimentare cu click-dreapta, Properties. Pe lng detalii legate de comportamentul ateptat, sunt incluse i evaluri ale timpului de execuie al metodelor testate. n continuare, se face depanarea programului, se recompileaz i se ruleaz din nou testele n interfaa NUnit. La apsarea butonului Run, assembly-ul este rencrcat, deci testele se vor face pe noua variant a programului. Clasa de test poate conine cmpuri proprii. Dac este nevoie de iniializarea lor nainte de rularea celorlalte metode de test, iniializarea se realizeaz ntr-o metod marcat cu atributul [SetUp]. De exemplu:
[TestFixture] public class AccountTest { Account _source; Account _destination; [SetUp] public void Init() { _source = new Account(); _source.Deposit(200.00f); _destination = new Account(); _destination.Deposit(150.00f); } [Test] public void TransferFunds() { _source.TransferFunds(_destination, 100.00f); Assert.AreEqual(250.00f, _destination.Balance); Assert.AreEqual(100.00f, _source.Balance); } }

248
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 13. Testarea unitilor cu NUnit

NUnit permite ca o metod s fie rulat dup terminarea tuturor testelor prin marcarea ei cu atributul [TearDown]. Acest metod se poate folosi de exemplu pentru dezalocarea unor resurse utilizate la teste. O clas de test poate avea doar o singur metod SetUp i doar o singur metod TearDown. Dac sunt definite mai multe, programul va compila, dar testele nu vor rula. Metoda TearDown nu va rula dac metoda SetUp eueaz sau arunc o excepie. n concluzie, testele NUnit pot fi create fr a modifica programul testat i pot fi eliminate n varianta pregtit pentru lansare. Clasa Assert este utilizat de obicei pentru compararea rezultatelor ateptate cu cele reale. Metoda care testeaz egalitatea este cea mai folosit. De fiecare dat cnd proiectul se modific, testele unitilor trebuie rulate din nou pentru a verifica dac funcionalitatea existent nu a fost afectat.

4. Aplicaii
4.1. Implementai programul cu operaii aritmetice prezentat mai sus. Creai cazurile de test descrise i rulai-le n interfaa NUnit. 4.2. Realizai un program care calculeaz numrul de zile diferen ntre un moment referin ales arbitrar (1 ianuarie 2000) i o dat introdus de utilizator. Diferena de zile ntre oricare dou date poate fi calculat prin adunarea sau scderea rezultatelor obinute prin dou apeluri succesive ale acestei funcii. Nu se vor folosi clasele specializate din C# gen DateTime. Date de intrare: o dat calendaristic n formatul zi / lun / an. Date de ieire: diferena de zile (pozitiv sau negativ). Se vor considera cazurile de test din tabelul 13.1.
Tabelul 13.1. Cazuri de test
Data 4.07.2003 29.02.2100 10.05.2000 5.01.2000 15.10.3404 2.01.2009 30.04.1972 Rezultat corect 1280 dat invalid 130 4 513088 3289 -10107 249
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C# Data 15.12.1999 1.01.1976 5.11.1997 20.03.79 32.12.1988 Rezultat corect -17 -8766 -787 -701552 dat invalid

Diagramele UML ale celor dou clase sunt prezentate n figura 13.2.

Figura 13.2. Diagrama UML a clasei Zile i cea a clasei de test

Indicaii: Problema principal la calcularea diferenei de zile este determinarea numrului de ani biseci. Regula pentru a determina dac un an este bisect este urmtoarea: anul este divizibil cu 4, dar nu este divizibil cu 100 sau este divizibil cu 400. De exemplu, anul 1900 nu a fost bisect iar 2000 a fost an bisect pentru c este divizibil cu 400. Se poate utiliza secvena urmtoare de cod:
int[] nrzile = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; if (_an % 4 == 0 && _an % 100 != 0 || _an % 400 == 0) nrzile[1] = 29;

Proprietatea Diferenta este readonly (are numai accesorul get). Metoda Calculeaza arunc o excepie dac data este invalid.

250
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 13. Testarea unitilor cu NUnit

O alternativ la aceast proiectare a clasei Zile este declararea unei metode statice de tipul:
public static int CalculeazaDiferenta(int zi, int luna, int an)

n acest fel, s-ar evita posibila aruncare a unei excepii la instanierea unui obiect Zile, situaie care nu este foarte elegant. Realizai mai nti cazurile de test i apoi implementai metodele clasei Zile, verificnd la fiecare modificare rezultatele n interfaa vizual NUnit.

251
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

252
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 14

Rapoarte de testare
1. Obiective 2. Testarea unei ierarhii de clase 3. Aplicaie

1. Obiective
Scopul capitolului 14 este prezentarea unei modaliti de utilizare a platformei NUnit pentru testarea unei ierarhii de clase fr duplicarea codului de test i realizarea unui raport de testare complet pentru o problem (aparent) simpl de clasificare a triunghiurilor.

2. Testarea unei ierarhii de clase


S considerm un program care indic tipul unui triunghi pe baza lungimilor laturilor sale: scalen (oarecare), isoscel (dou laturi egale), echilateral (toate trei laturi egale). Programul mai trebuie s verifice dac triunghiul determinat de cele trei valori este un triunghi valid. Avem patru variante de clase: Triangle1, Triangle2, Triangle3 i Triangle4 (figura 14.1), toate cu aceeai structur, fiind diferite doar implementrile metodelor.

Figura 14.1. Ierarhia claselor care trebuie testate


253
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

Vor fi necesare mai multe teste pentru fiecare tip de triunghi, cu exact acelai cod, adic aceleai valori ale laturilor i rezultate ateptate. De aceea, pentru a nu repeta de patru ori acelai cod de test, putem scrie nite teste generice pentru interfaa ITriangle. n plus, putem optimiza modul de verificare a rezultatelor, deoarece sunt patru metode care trebuie testate: IsScalene, IsIsosceles, IsEquilateral i IsInvalid. Astfel, putem crea o metod care s apeleze toate cele patru metode i s returneze un ir de caractere care s codeze rezultatele tuturor acestor metode:
private string EvaluateTriangle() { if (_triangle.IsInvalid()) return "0"; string s = ""; if (_triangle.IsScalene()) s += "1"; else s += "0"; if (_triangle.IsIsosceles()) s += "1"; else s += "0"; if (_triangle.IsEquilateral()) s += "1"; else s += "0"; return s; }

Pentru un triunghi invalid, metoda va returna "0", pentru un triunghi oarecare (scalen), metoda va returna "100", pentru un triunghi isoscel va returna "010" iar pentru un triunghi echilateral "001". Din cauza faptului c metodele testate au erori, pot aprea rezultate incorecte, precum "101". Clasa de testare generic a interfeei ITriangle va avea urmtoarea form:

254
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 14. Rapoarte de testare // [TestFixture] public class TriangleTest { protected ITriangle _triangle; [Test] public void ValidScalene() { // 1. Scalen valid _triangle.SetSides(10, 8, 5); Assert.AreEqual("100", EvaluateTriangle(), "10-8-5"); } // ... celelalte teste }

Se remarc faptul c aceast clas nu are atributul [TestFixture], deoarece testele vor fi realizate doar pentru tipurile concrete. n acest scop, vom deriva patru clase din clasa TriangleTest, cte una pentru fiecare tip de triunghi. n metoda marcat cu atributul [SetUp] vom iniializa cmpul _triangle. n continuare, platforma NUnit va rula testele din clasa Triangle1Test, motenite din clasa de baz TriangleTest, avnd cmpul _triangle de tipul triunghiului concret Triangle1.
[TestFixture] public class Triangle1Test : TriangleTest { [SetUp] public void Init() { _triangle = new Triangle1(); } }

n mod similar se procedeaz i pentru celelalte tipuri concrete. Rezultatele testrii vor aprea ca n figura 14.2.

255
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

Figura 14.2. Rezultatele testrii cu NUnit

3. Aplicaie
3.1. Se dorete testarea cutie neagr (engl. black box) a claselor de triunghiuri descrise anterior. Folosii platforma NUnit pentru a testa toate cazurile de eroare care pot aprea. Vom considera c dac triunghiul este valid, o singur metod trebuie s fie activ la un moment dat. De exemplu, considerm c un triunghi echilateral nu este n acelai timp i isoscel. Implementrile claselor din ierarhia de triunghiuri sunt prezentate n continuare.
namespace TestTriangles { public interface ITriangle { bool IsInvalid(); bool IsScalene(); bool IsIsosceles(); bool IsEquilateral(); void SetSides(int a, int b, int c); } }

256
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 14. Rapoarte de testare namespace TestTriangles { public class Triangle1 : ITriangle { int _a; int _b; int _c; bool _flag; public void SetSides(int a, int b, int c) { _a = a; _b = b; _c = c; int semiperim = (a + b + c) / 2; _flag = a == 0 || b == 0 || c == 0 || a < 0 || b < 0 || c < 0 || semiperim <= a || semiperim <= b || semiperim <= c; } public bool IsInvalid() { return _flag; } public bool IsScalene() { return _a != _b && _a != _c && _b != _c; } public bool IsIsosceles() { return _a == _b || _a == _c || _b == _c; } public bool IsEquilateral() { return _a == _b && _b == _c && !IsIsosceles(); } } } namespace TestTriangles { public class Triangle2 : ITriangle { int _a; 257
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C# int _b; int _c; bool _flag; public void SetSides(int a, int b, int c) { _a = a; _b = b; _c = c; int semiperim = (a + b + c) / 2; _flag = a == 0 || b == 0 || c == 0; } public bool IsInvalid() { return _flag; } public bool IsScalene() { return _a != _b && _a != _c && _b != _c; } public bool IsIsosceles() { return _a == _b || _a == _c || _b == _c; } public bool IsEquilateral() { return _a == _b && _b == _c; } } } namespace TestTriangles { public class Triangle3 : ITriangle { int _a; int _b; int _c; bool _flag;

258
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 14. Rapoarte de testare public void SetSides(int a, int b, int c) { _a = a; _b = b; _c = c; int semiperim = (a + b + c) / 2; _flag = a < 0 || b < 0 || c < 0; } public bool IsInvalid() { return _flag; } public bool IsScalene() { return _a != _b && _a != _c && _b != _c; } public bool IsIsosceles() { return _a == _b || _a == _c || _b == _c; } public bool IsEquilateral() { return _a == _b && _b == _c; } } } namespace TestTriangles { public class Triangle4 : ITriangle { int _a; int _b; int _c; bool _flag; public void SetSides(int a, int b, int c) { _a = a; _b = b; _c = c; int semiperim = (a + b + c) / 2; 259
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C# _flag = a == 0 || b == 0 || c == 0 || a < 0 || b < 0 || c < 0; } public bool IsInvalid() { return _flag; } public bool IsScalene() { return _a != _b && _a != _c && _b != _c; } public bool IsIsosceles() { return _a == _b || _a == _c || _b == _c; } public bool IsEquilateral() { return _a == _b && _b == _c; } } }

Creai un raport de testare pentru fiecare clas. Raportul va avea structura din tabelul 14.1.
Tabelul 14.1. Raport de testare
Nr. test 1 2 Valori laturi 355 333 Rspuns corect Isoscel Echilateral ... Rspuns program Scalen, Isoscel Echilateral Observaii incorect corect

Scopul este s descoperii ct mai multe cazuri de test, cu valori att corecte ct i incorecte. O list cuprinztoare a cazurilor de test este dat n figura 14.3. Consultai-o doar dup ce ai ncercat propriile cazuri.

260
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Capitolul 14. Rapoarte de testare

Figura 14.3. Exemplu de rezolvare: cazuri de test

261
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

262
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Referine
[1] Albahari, J. (2008). C# Concepts: Value vs Reference Types, http://www.albahari.com/valuevsreftypes.aspx [2] Altova Umodel (2008). UModel tutorial, http://www.altova.com/ manual2008/UModel/umodelprofessional [3] Ariadne Training (2008). UML Applied, 2nd edition, http://ariadnetraining.com [4] Becker, K. (2008). Using the Model View Controller Pattern in C# ASP .NET Web Applications, http://www.primaryobjects.com/CMS/ Article82.aspx [5] Data & Object Factory (2002). Software Design Patterns, http://www.dofactory.com/Patterns/Patterns.aspx [6] Fowler, M. (2006). Passive View, http://martinfowler.com/eaaDev/ PassiveScreen.html [7] Fowler, M. (2006). Supervising Controller, http://martinfowler.com/ eaaDev/SupervisingPresenter.html [8] Freeman, E., Freeman, E., Bates, B., Sierra, K. (2004). Head First Design Patterns, O'Reilly Media, Inc. [9] Gamma, E., Helm, R., Johnson, R., Vlissides, J. M. (1994). Design Patterns: Elements of Reusable Object-Oriented Software, AddisonWesley Professional [10] Goodliffe, P. (2006). Code Craft: The Practice of Writing Excellent Code, No Starch Press [11] Hilyard, J., Teilhet, S. (2006). C# Cookbook, 2nd Edition, O'Reilly [12] Liptchinsky, V. (2008). Pre-compile (pre-JIT) your assembly on the fly, or trigger JIT compilation ahead-of-time, http://www.codeproject.com/ Articles/31316/Pre-compile-pre-JIT-your-assembly-on-the-fly-or-tr [13] Microsoft MSDN Library (2008-2011). Paginile despre clase, structuri, enumeraii, Model-View-Controller, Model-View-Presenter, clase pariale, proprieti, clase abstracte, interfee, polimorfism, http://msdn.microsoft.com/en-us/library/default.aspx

263
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

Florin Leon Aplicaii de ingineria programrii n C#

[14] MSDN Forum (2008). Faster Deep Cloning, http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/ thread/5e13351f-abdb-42d4-93f0-64bff65b8d74 [15] MVCSharp Org. (2011). MVC# Overview, http://www.mvcsharp.org/ Overview/Default.aspx [16] Myers, G. J., Sandler, C., Badgett, T., Thomas, T. M. (2004). The Art of Software Testing, 2nd edition, Wiley [17] Obviex (2010). How To: Encrypt and Decrypt Data Using a Symmetric (Rijndael) Key (C#/VB.NET), http://www.obviex.com/samples/ Encryption.aspx [18] SmartForce Ireland Ltd & Classic Systems Solutions (1999). GUI Design Fundamentals [19] SpiderWorks Technologies (2011). C# Coding Standards and Best Programming Practices, http://www.dotnetspider.com/tutorials/ BestPractices.aspx [20] Wikipedia, The Free Encyclopedia (2008). Paginile despre CIL/MSIL, Reflector .NET, DLL, DLL hell, Unit testing, Model-View-Controller, Just-in-time_compilation, http://en.wikipedia.org [21] Ziff Davis, Inc. (2009). Adopting C#, and Eluding DLL Hell, http://www.extremetech.com/article2/0,2845,1153065,00.asp

264
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6 http://florinleon.byethost24.com

You might also like