IP04_Proiectarea
IP04_Proiectarea
4. Faza de proiectare
Florin Leon
Universitatea Tehnică „Gheorghe Asachi” din Iași
Facultatea de Automatică și Calculatoare
[Link]
v2023.1
Faza de proiectare
1. Introducere
2. Arhitectura software
3. Proiectarea modulelor
4. Metrici de proiectare
5. Principii de proiectare
6. Șabloane de proiectare
7. Concluzii
6
Florin Leon, Ingineria programarii, [Link]
Nivelurile proiectării
Clase și tipuri de date
Proiectare mai puțin formală, mai ușor de schimbat
Tot trebuie să existe o fază distinctă de proiectare
Metode / funcții
Mai degrabă un exercițiu mental decât o procedură
documentată
Proiectarea explicită este necesară pentru algoritmi
deosebiți
7
Florin Leon, Ingineria programarii, [Link]
Compromisuri
Extensibilitate vs. simplitate
Niveluri suplimentare de generalitate
Eficiență vs. claritate
Creșterea cuplării pentru evitarea accesului indirect
Sistemele optimizate sunt mai puțin clare
Număr de trăsături vs. efort de dezvoltare
Mai multe trăsături au nevoie de mai mult efort
Prioritizarea depinde de cerințele proiectului
8
Florin Leon, Ingineria programarii, [Link]
Abordarea recomandată
Iterativă
Proiectare incrementală
Prudentă
Pași mici, număr limitat de decizii, localizarea erorilor
Realistă
Aplicarea metodologiilor, dar și utilizarea experienței
Rezultatul depinde de calitatea specificațiilor, experiența echipei
și rigoarea aplicării procedurilor
Informată
Trebuie înțelese complet cerințele și principiile problemei
Altfel, se poate rezolva altă problemă
9
Florin Leon, Ingineria programarii, [Link]
Faza de proiectare
1. Introducere
2. Arhitectura software
3. Proiectarea modulelor
4. Metrici de proiectare
5. Principii de proiectare
6. Șabloane de proiectare
7. Concluzii
13
Florin Leon, Ingineria programarii, [Link]
Modelul 4+1 al
perspectivelor arhitecturii
15
Florin Leon, Ingineria programarii, [Link]
Faza de proiectare
1. Introducere
2. Arhitectura software
3. Proiectarea modulelor
4. Metrici de proiectare
5. Principii de proiectare
6. Șabloane de proiectare
7. Concluzii
18
Florin Leon, Ingineria programarii, [Link]
Niveluri de cuplare
Cuplare prin conținut
Cuplare prin structuri comune
Cuplare prin control
Cuplare prin marcaj
Cuplare prin date
19
Florin Leon, Ingineria programarii, [Link]
Cuplarea prin conținut
Modulele partajează codul: se int Func1(int a)
{
poate „sări” dintr-un modul în printf("In Func1\n");
a++;
codul celuilalt modul goto F2A;
return a;
Limbajele moderne de }
programare nu permit acest
lucru void Func2()
{
printf("In Func2\n");
F2A:
printf("At Func2A\n");
}
20
Florin Leon, Ingineria programarii, [Link]
Cuplarea prin structuri comune
Modulele referențiază aceleași structuri de date globale (common
coupling) sau aceleași variabile globale (external coupling)
Module A
ReadCustomerRecord()
{
Read(customerRecord); Structura de date comună
if (eof) este customerRecord
eofFlag = true;
}
ModuleB
ValidateCustomerRecord()
{
if ([Link] is not numeric)
{
errorMessage = "invalid customer number";
PrintErrorReport();
}
} 21
Florin Leon, Ingineria programarii, [Link]
Cuplarea prin control
Un modul trimite celuilalt modul o variabilă de control
care îi determină fluxul de execuție
Module A
ProcessInputCode()
{
Read(inputCode);
ChooseAppropriateAction(inputCode);
}
Module B
ChooseAppropriateAction(inputCode)
{
switch (inputCode)
{
case 1: ReadEmployeeRecord();
case 2: PrintPageHeadings();
case 3: OpenEmployeeMasterFile();
case 4: errorMessage = "Employee number not numeric";
} 22
}
Florin Leon, Ingineria programarii, [Link]
Cuplarea prin marcaj
Un modul trimite celuilalt modul o structură de date
ca parametru
Module A
ProcessTransactionRecord()
{
if (transactionRecord is for a male)
ProcessMaleStudent(currentRecord);
else
ProcessFemaleStudent(currentRecord);
}
Module B
ProcessMaleStudent(currentRecord)
{
Structura de date trimisă este maleStudentCount++;
currentRecord if ([Link] > 21)
matureMaleCount++;
}
23
Florin Leon, Ingineria programarii, [Link]
Cuplare prin date
Un modul trimite celuilalt modul variabile ca parametri
Module A
ProcessCustomerRecord()
{
CalculateSalesTax(totalPrice, salesTax);
}
Module B
CalculateSalesTax(totalPrice, salesTax)
{
if (totalPrice < 10)
salesTax = totalPrice * 0.25;
else if (totalPrice < 100)
salesTax = totalPrice * 0.3;
else
salesTax = totalPrice * 0.4;
}
24
Florin Leon, Ingineria programarii, [Link]
Factori ce afectează cuplarea
Gradul de cuplare dintre două module depinde
de complexitatea interfațării lor
Scop: cuplare slabă
Minimizarea numărului de interfețe ale unui modul
Minimizarea complexității interfețelor (numărul de
parametri)
Trimiterea ca parametri numai a câmpurilor necesare,
nu a unui întreg obiect
Evitarea comunicațiilor hibride: date și control
25
Florin Leon, Ingineria programarii, [Link]
Factori ce afectează cuplarea
Control
26
Florin Leon, Ingineria programarii, [Link]
Cuplarea în sisteme orientate
pe obiecte
Cuplarea prin interacțiune
Se referă la apelul dintr-o metodă a unei clase
a unei metode din altă clasă
Accesarea secțiunilor interne violează principiul
încapsulării: câmpuri publice, conceptul de friend
din C++
Folosirea câmpurilor pentru a stoca date
temporare și nu starea obiectelor
Metodele comunică doar prin parametri: sunt
trimise numai date și numai variabilele necesare
27
Florin Leon, Ingineria programarii, [Link]
Cuplarea în sisteme orientate
pe obiecte
Cuplarea prin compunere
O clasă folosește instanțe ale altor clase
Câmpuri, parametri: cuplare mai slabă
Variabile locale, invizibile din exterior: cuplare mai
puternică
28
Florin Leon, Ingineria programarii, [Link]
Cuplarea în sisteme orientate
pe obiecte
Cuplarea prin moștenire
Moștenirea poate reduce cuplarea generală din
sistem
A cuplată cu B, B are subclasele C, D
Dacă o metodă m este „ridicată” din C și D în B,
A va fi cuplată numai cu B, nu cu C și D
Pot fi adăugate fără probleme noi subclase ale lui B
Cuplarea minimă are loc când clasele derivate nu
modifică metodele moștenite, ci doar adaugă noi
metode
29
Florin Leon, Ingineria programarii, [Link]
Coeziunea
Coeziunea arată cât de apropiate sunt elementele
aceluiași modul
Scop: coeziune puternică
În general, o coeziune puternică este corelată cu o cuplare slabă
Întrucât există mai multe niveluri de coeziune
(prezentate în continuare), coeziunea unui modul se
consideră a fi nivelul maxim de coeziune aplicabil
elementelor acestuia
De exemplu, scopul unei clase este adesea definit de metoda sa
cu o coeziune maximă, iar celelalte metode sprijină acest scop
30
Florin Leon, Ingineria programarii, [Link]
Niveluri de coeziune
Coeziune prin coincidență
Coeziune logică
Coeziune temporală
Coeziune procedurală
Coeziune comunicațională
Coeziune secvențială
Coeziune funcțională
31
Florin Leon, Ingineria programarii, [Link]
Coeziunea prin coincidență
Coeziunea prin coincidență se referă la situațiile în care
o clasă are metode care nu au legătură între ele și nu au
un scop comun
Module create doar pentru a evita duplicarea codului din mai
multe secțiuni
Module rezultate prin partiționarea artificială a altor module (de
exemplu, conform criteriului ca un modul să respecte un număr
maxim permis de instrucțiuni)
Combinarea mai multor module pentru a reduce numărul
modulelor din program sau pentru a respecta un număr minim de
instrucțiuni pe modul
32
Florin Leon, Ingineria programarii, [Link]
Coeziunea prin coincidență:
exemplu
public class Utils
{
public int GenerateRandomNumber()
33
Florin Leon, Ingineria programarii, [Link]
Coeziunea logică
Coeziunea logică se referă la situațiile în care o clasă
are metode care îndeplinesc sarcini similare, dar nu
neapărat legate de un concept unic
Un modul conține funcții care aparțin aceleiași clase logice, adică
toate elementele sale realizează operații similare, de exemplu,
tratarea tuturor intrărilor sau ieșirilor
Poate fi nevoie de o variabilă de control care să determine ce
instrucțiuni se execută în fiecare caz (informațiile hibride cresc
cuplarea)
34
Florin Leon, Ingineria programarii, [Link]
Coeziunea logică: exemplu
public class Customer
{
public Customer(string name, int age, double balance)
35
Florin Leon, Ingineria programarii, [Link]
Coeziunea temporală
Coeziunea temporală se referă la situațiile în care o
clasă are metode care sunt legate între ele de momentul
când trebuie executate, mai degrabă decât de un scop
comun
Coeziunea temporală poate fi privită ca un tip de coeziune logică
în care timpul este elementul comun
Modulele conțin funcții asociate în timp
De obicei, sunt module de inițializare sau finalizare, iar
elementele sunt executate toate împreună
36
Florin Leon, Ingineria programarii, [Link]
Coeziunea temporală: exemplu
public class FileDownloader
{
public void Start()
37
Florin Leon, Ingineria programarii, [Link]
Coeziunea procedurală
Coeziunea procedurală apare atunci când metodele
dintr-o clasă sunt legate între ele printr-o succesiune de
pași dintr-un procedură
Modulele conțin funcții care aparțin unei unități procedurale
comune, de exemplu, unele părți dintr-un modul sunt puse într-un
nou modul: un bloc de decizie mai mare sau un bloc iterativ sunt
plasate într-o altă metodă
Un modul poate avea doar părți dintr-o funcție completă
Un alt exemplu este o metodă care execută alte metode într-o
anumită ordine, conform unei proceduri
38
Florin Leon, Ingineria programarii, [Link]
Coeziunea procedurală:
exemplu
public class OrderProcessor
{
public OrderProcessor(Order order)
39
Florin Leon, Ingineria programarii, [Link]
Coeziunea comunicațională
Coeziunea comunicațională apare atunci când metodele
unei clase sunt legate prin datele pe care efectuează
operații sau prin mesajele pe care le schimbă
Toate elementele unui modul operează cu aceleași date, de
exemplu: găsește titlul unei cărți, respectiv autorul, editura, prețul
Acest tip de coeziune este acceptabil, dar are dezavantajul că
asupra acelorași date se pot efectua operații neînrudite
40
Florin Leon, Ingineria programarii, [Link]
Coeziunea comunicațională:
exemplu
public class EmailSender
{
private SmtpClient _smtpClient;
private MailMessage _message;
public EmailSender(string smtpServer, int port, string username, string password) // inițializează _smtpClient
public void ComposeMessage(string from, string to, string subject, string body) // instanțiază _message
41
Florin Leon, Ingineria programarii, [Link]
Coeziunea secvențială
Coeziunea secvențială apare atunci când când metodele
unei clase sunt legate între ele prin efectuarea unei
secvențe de operații, în care ieșirea unei operații
servește ca intrare pentru următoarea operație
Un modul conține elemente care depind de prelucrarea
anterioară a altor elemente
Coeziunea temporală descrie metode care sunt legate de
momentul în care sunt executate, în timp ce coeziunea
secvențială descrie metode care sunt legate de ordinea lor de
execuție
Coeziunea procedurală se concentrează pe efectuarea unei
secvențe de operații care sunt legate de realizarea unei sarcini
sau scop general, dar în care fiecare operație este independentă
de celelalte 42
Florin Leon, Ingineria programarii, [Link]
Coeziunea secvențială:
exemplu
public class FileParser
{
public void SetFilePath(string path)
public void SaveResults() // se salvează rezultatele parsate în alt fișier sau într-o bază de date
}
43
Florin Leon, Ingineria programarii, [Link]
Coeziunea funcțională
Coeziunea funcțională apare atunci când metodele unei
clase îndeplinesc o sarcină specifică, clar definită și
legată de un singur concept
Toate elementele unui modul sunt utilizate pentru efectuarea
unei singure funcții
44
Florin Leon, Ingineria programarii, [Link]
Coeziunea funcțională:
exemplu
public class Recipe
{
public void AddIngredient(string ingredient)
45
Florin Leon, Ingineria programarii, [Link]
Comparație
46
Florin Leon, Ingineria programarii, [Link]
Coeziunea în sisteme orientate
pe obiecte
Coeziunea metodelor
Fiecare metodă implementează o funcție clar definită
Coeziunea claselor
Justifică de ce sunt împreună atributele și operațiile în aceeași
clasă
O clasă reprezintă un concept, dacă nu, metodele și câmpurile
pot fi partiționate în mai multe clase
Coeziunea moștenirilor
Coeziunea este mare dacă ierarhia urmărește generalizarea-
specializarea unui concept
Coeziunea este mică dacă scopul ierarhiei este doar partajarea
codului
47
Florin Leon, Ingineria programarii, [Link]
Faza de proiectare
1. Introducere
2. Arhitectura software
3. Proiectarea modulelor
4. Metrici de proiectare
5. Principii de proiectare
6. Șabloane de proiectare
7. Concluzii
Metrici:
Complexitatea ciclomatică
Metrica de coeziune
49
Florin Leon, Ingineria programarii, [Link]
Complexitatea ciclomatică
Ideea de bază:
Considerând două programe cu aceeași dimensiune, programul
cu mai multe instrucțiuni de decizie este probabil mai complex
Complexitatea ciclomatică: M = e – n + 2p
n = numărul de noduri
e = numărul de arce
p = numărul de componente conexe (pentru un modul, este 1)
Numărul ciclomatic: V = e – n + p
Dacă se adaugă un arc de la nodul final la nodul inițial,
astfel încât graful să devină tare conex, M = V
50
Florin Leon, Ingineria programarii, [Link]
Exemplul 1
M = 10 – 7 + 1 = 4
51
Florin Leon, Ingineria programarii, [Link]
Exemplul 2
public string Test1(int x) public string Test2(int x)
{ {
switch (x) var retValues = new string[] { "a", "b", "c", "d", "e", "f" };
{ if (x > 0 && x <= 6)
case 1: return "a"; {
case 2: return "b"; return retValues[x - 1];
case 3: return "c"; }
case 4: return "d"; return "other";
case 5: return "e"; }
case 6: return "f";
}
return "other";
}
M=7 M=3
52
Florin Leon, Ingineria programarii, [Link]
Efecte
Complexitatea ciclomatică a unui modul este
numărul de decizii + 1
Recomandare: M < 10
M este o estimare a numărului de căi care trebuie
testate în faza de testare
Această metrică este corelată cu dimensiunea
modulului și cu numărul de defecte
53
Florin Leon, Ingineria programarii, [Link]
.NET Reflector
54
Florin Leon, Ingineria programarii, [Link]
.NET Reflector
55
Florin Leon, Ingineria programarii, [Link]
Metrica de coeziune
Ideea de bază este de a vedea cum sunt folosite
variabilele unui modul de către codul modulului
Se construiește graful fluxului de control al modulului
I este nodul inițial
T este nodul final
Fiecare nod Si este adnotat cu variabilele pe care le
referențiază
Se utilizează acest graf pentru a calcula mulțimile de
referințe pentru fiecare variabilă: Ri = mulțimea de noduri
care referențiază variabila i a modulului
56
Florin Leon, Ingineria programarii, [Link]
Metrica de coeziune
Pentru fiecare Ri , se calculează coeziunea:
unde:
dim(S) este numărul tuturor căilor independente de la I la T
care includ cel puțin o instrucțiune din mulțimea S
G este mulțimea tuturor instrucțiunilor din modúl care
referențiază cel puțin o variabilă
Dacă S = G, atunci dim(S) este complexitatea ciclomatică a
modulului
Altfel, dim(S) este numărul de decizii din mulțimea de instrucțiuni
+ 1 (complexitatea ciclomatică a mulțimii de instrucțiuni)
57
Florin Leon, Ingineria programarii, [Link]
Metrica de coeziune
Coeziunea unui modul cu n variabile este:
58
Florin Leon, Ingineria programarii, [Link]
Exemplu (același program)
j nu apare pe calea 2
A nu apare pe căile 2 și 3
59
Florin Leon, Ingineria programarii, [Link]
Faza de proiectare
1. Introducere
2. Arhitectura software
3. Proiectarea modulelor
4. Metrici de proiectare
5. Principii de proiectare
6. Șabloane de proiectare
7. Concluzii
SOLID
Single responsibility principle
Open-closed principle
Liskov substitution principle
Interface segregation principle
Dependency inversion principle
61
Florin Leon, Ingineria programarii, [Link]
Principiul deschis-închis
O clasă trebuie să fie deschisă pentru
extindere, dar închisă pentru modificări
(Bertrand Meyer, 1998)
Codul nou trebuie adăugat ușor, dar fără a
modifica codul existent
62
Florin Leon, Ingineria programarii, [Link]
Exemplu: problemă
public class Rectangle se adaugă public class Circle
{ alte forme {
public double Width { get; set; } geometrice public double Radius { get; set; }
public double Height { get; set; } }
}
public static double Area(object[] shapes)
public class AreaCalculator {
{ double area = 0;
public static double Area(Rectangle[] shapes) foreach (var shape in shapes)
{ {
double area = 0; if (shape is Rectangle)
foreach (var shape in shapes) {
{ Rectangle rectangle = (Rectangle)shape;
area += [Link] * [Link]; area += [Link] * [Link];
} }
return area; else
} {
} Circle circle = (Circle)shape;
area += [Link] * [Link] * [Link];
}
return area;
}
} 63
Florin Leon, Ingineria programarii, [Link]
Exemplu: soluție
public abstract class Shape public class Circle : Shape
{ {
public abstract double Area(); public double Radius { get; set; }
}
public override double Area()
public class Rectangle : Shape {
{ return Radius * Radius * [Link];
public double Width { get; set; } }
public double Height { get; set; } }
64
Florin Leon, Ingineria programarii, [Link]
Principiul substituției
Subclasele trebuie să fie substituibile claselor
lor de bază (Barbara Liskov, 1997)
Metodele care folosesc instanțe ale unor clase de
bază trebuie să poată folosi și instanțe ale
claselor derivate cu același efect
O clasă derivată trebuie să facă tot ceea ce face
clasa ei de bază (și ceva în plus)
65
Florin Leon, Ingineria programarii, [Link]
Exemplul 1: rața electrică
public interface IDuck
{
void Swim();
}
67
Florin Leon, Ingineria programarii, [Link]
Cazul 1
private static void Print(Ellipse e)
{
[Link]("Ellipse: rx = {0}, ry = {1}, a = {2:F2}", [Link], [Link], [Link]);
}
68
Florin Leon, Ingineria programarii, [Link]
Cazul 1
private static void Main(string[] args)
{
Ellipse e = new Ellipse(1, 2);
[Link]("Ellipse r = new Ellipse() -> Type " + [Link]().Name);
Print(e);
[Link](3);
Print(e);
[Link]();
Ellipse r = new Ellipse() -> Type Ellipse
Circle c = new Circle(1); Ellipse: rx = 1, ry = 2, a = 6.28
[Link]("Circle s = new Circle() -> Type " + [Link]().Name); Ellipse: rx = 3, ry = 2, a = 18.85
Print(c);
[Link](3); Circle s = new Circle() -> Type Circle
Print(c); Circle: rx = 1, (ry = 1), a = 3.14
[Link](); Circle: rx = 1, (ry = 1), a = 3.14
public Circle(int r)
{
R = r;
}
74
Florin Leon, Ingineria programarii, [Link]
Soluția 2 (clase imutabile)
public class Ellipse
{
public int Rx { get; set; }
public int Ry { get; set; }
75
Florin Leon, Ingineria programarii, [Link]
Soluția 2 (clase imutabile)
public class Circle : Ellipse
{
public Circle(int r) : base(r, r)
{
}
76
Florin Leon, Ingineria programarii, [Link]
Soluția 2
private static void Main(string[] args)
{
Ellipse e = new Ellipse(1, 2);
Print(e);
e = [Link](3);
Print(e);
[Link](); Ellipse: rx = 1, ry = 2, a = 6.28
Ellipse: rx = 3, ry = 2, a = 18.85
Circle c = new Circle(1);
Print(c); Circle: rx = 1, (ry = 1), a = 3.14
e = [Link](3); Ellipse: rx = 3, ry = 1, a = 9.42
Print(e);
[Link](); Ellipse: rx = 1, ry = 1, a = 3.14
Ellipse: rx = 3, ry = 1, a = 9.42
Ellipse ec = c;
Print(ec); toate rezultatele sunt corecte,
ec = [Link](3); generalizarea este corectă,
Print(ec); iar cercurile pot fi convertite
[Link](); în elipse
}
77
Florin Leon, Ingineria programarii, [Link]
Principiul inversiunii dependențelor
Clasele de nivel înalt nu trebuie să depindă
de clasele de nivel scăzut. Ambele trebuie să
depindă de abstracțiuni
Abstracțiunile nu trebuie să depindă de detaliile
concrete. Detaliile concrete trebuie să depindă de
abstracțiuni
78
Florin Leon, Ingineria programarii, [Link]
Exemplu: problemă
public class Worker public class SuperWorker
{ {
public void Work() public void Work()
{ {
// working // working more
} }
} }
80
Florin Leon, Ingineria programarii, [Link]
Principiul responsabilității unice
O clasă trebuie să aibă un singur motiv să se
modifice
O clasă trebuie să facă un singur lucru
81
Florin Leon, Ingineria programarii, [Link]
Exemplu: problemă
public class Customer
{
public void Add()
{
try
{
// database code
}
catch (Exception ex)
{
[Link]("[Link]", [Link]());
}
}
}
82
Florin Leon, Ingineria programarii, [Link]
Exemplu: soluție
public class Customer public class FileLogger
{ {
private FileLogger _logger = new FileLogger(); public void Handle(string error)
{
public void Add() [Link]("[Link]", error);
{ }
try }
{
// database code
}
catch (Exception ex)
{
_logger.Handle([Link]());
}
}
}
83
Florin Leon, Ingineria programarii, [Link]
Principiul segregării interfețelor
Mai multe interfețe specifice pentru clienți
sunt mai bune decât o singură interfață de
uz general
Un client nu trebuie forțat să depindă de metode
pe care nu le folosește
84
Florin Leon, Ingineria programarii, [Link]
Exemplu public interface IPrinter
{
public interface IMachine void Print(List<Item> item);
{ }
void Print(List<Item> item);
void Staple(List<Item> item); public interface IStaple
void Fax(List<Item> item); {
void Scan(List<Item> item); void Staple(List<Item> item);
void PhotoCopy(List<Item> item); }
}
public interface IFax
{
void Fax(List<Item> item);
}
86
Florin Leon, Ingineria programarii, [Link]
Principii suplimentare
Principiul echivalenței lansare-reutilizare (release-reuse)
Granula pentru reutilizare este granula pentru lansare
Clasele reutilizabile trebuie grupate în pachete care pot fi
gestionate pe măsură ce versiunile evoluează
Principiul închiderii comune (common closure)
Clasele care se modifică împreună trebuie grupate împreună
Clasele trebuie grupate astfel încât coeziunea să fie mare
Principiul reutilizării comune (common reuse)
Clasele care nu sunt reutilizate împreună nu trebuie grupate
împreună
Clasele care se modifică determină o nouă versiune a întregului
pachet
87
Florin Leon, Ingineria programarii, [Link]
Euristici de proiectare
Dimensiunea unui modul este o indicație asupra
complexității acestuia
Modulele prea mari (≈ 100 linii) ar trebui partiționate
Modulele prea mici (≈ 2-3 linii) ar trebui combinate
...dar numai ținând cont de cuplarea și coeziunea
configurației rezultate
Fan-in (numărul de module care folosesc un modul)
și fan-out (numărul de module folosite de un modul)
Fan-in-ul trebuie maximizat
Fan-out-ul trebuie să fie < 5-6
88
Florin Leon, Ingineria programarii, [Link]
Caracteristicile unei proiectări
de calitate
Simplitatea
Cea mai importantă
Dimensiune redusă a codului
Codul bine proiectat pare evident, dar e greu de realizat
Eleganța
Aspect estetic
Fluxul de control este clar
Fiecare componentă adaugă ceva distinct
Lucrurile asemănătoare sunt asociate
Schimbările sunt localizate
Extensibilitatea
Structură logică și maleabilă
Interfețe, plug-in-uri dinamice
Echilibru: ce trebuie acum – ce va trebui în viitor – ce ar putea să
trebuiască în viitor
89
Florin Leon, Ingineria programarii, [Link]
Caracteristicile unei proiectări
de calitate
Modularitatea
Calitatea descompunerii
Lipsa duplicărilor
Copy-paste, apoi schimbările nu se fac în toate cazurile
Reinventarea roții
Generalizare: superclase, metode cu parametri
Portabilitatea
Nu trebuie compromisă calitatea codului dacă portabilitatea nu este
necesară
Abstractizarea secțiunilor neportabile (care depind de SO sau hardware)
Proiectare idiomatică
C++: supraîncărcarea operatorilor
C#: proprietăți
Proiectare bine documentată: specificații ale arhitecturii, API
90
Florin Leon, Ingineria programarii, [Link]
Faza de proiectare
1. Introducere
2. Arhitectura software
3. Proiectarea modulelor
4. Metrici de proiectare
5. Principii de proiectare
6. Șabloane de proiectare
7. Concluzii
92
Florin Leon, Ingineria programarii, [Link]
Bergen (Bryggen)
[Link] 93
Florin Leon, Ingineria programarii, [Link]
Bergen (Bryggen)
94
Florin Leon, Ingineria programarii, [Link]
Florența
[Link] 95
Florin Leon, Ingineria programarii, [Link]
Șabloane software
Soluții generale reutilizabile la probleme care
apar frecvent în proiectare
Sunt descrieri despre cum se poate rezolva o problemă
Nu pot fi transformate direct în cod
Un șablon este o soluție la o problemă într-un
context
Contextul: situațiile recurente în care se aplică șablonul
Problema: scopurile și constrângerile
Soluția: regula de proiectare
96
Florin Leon, Ingineria programarii, [Link]
Conținutul unui șablon
Numele Contextul rezultant:
Problema: obiectivele post-condițiile
Contextul: pre-condițiile Justificarea: cum
Forțele: constrângerile funcționează intern și
care indică un de ce (soluția – extern)
compromis, de unde și Șabloane înrudite
apare nevoia de șablon Exemple
Soluția: cum se ating Moduri de utilizare
obiectivele cunoscute
97
Florin Leon, Ingineria programarii, [Link]
Tipuri de șabloane
Șabloane arhitecturale
Nivelul arhitecturii
Șabloane de proiectare
Nivelul modulelor/claselor
Idiomuri
Nivelul limbajului de programare
98
Florin Leon, Ingineria programarii, [Link]
Arhitectura multi-strat
Fiecare strat poate fi
modificat sau înlocuit
în mod independent
poate fi la rândul
său multi-strat
99
Florin Leon, Ingineria programarii, [Link]
Arhitectura multi-nivel
Multi-strat = descompunere fizică:
dll, exe, mașini separate
100
Florin Leon, Ingineria programarii, [Link]
Arhitectura MVC
Model-Vizualizare-Controlor (Model-View-Controller, MVC)
101
Florin Leon, Ingineria programarii, [Link]
Varianta clasică
Modelul: conține datele, starea și logica aplicației. Deși nu
cunoaște Controlorul și Vizualizarea, furnizează o interfață
pentru manipularea și preluarea stării și poate trimite notificări cu
privire la schimbarea stării. De obicei primește cereri privind
starea datelor de la Vizualizare și instrucțiuni de modificare a
datelor sau stării de la Controlor
Vizualizarea: afișează Modelul într-o formă potrivită pentru
utilizator. Pentru un singur Model pot exista mai multe Vizualizări;
de exemplu, o listă de elemente poate fi afișată într-un control
vizual precum ListBox, într-o consolă sau într-o pagină web
Controlorul: primește intrările de la utilizator și apelează obiectele
Modelului pentru a prelucra noile informații
Pentru explicații suplimentare, vezi suportul de curs
102
Florin Leon, Ingineria programarii, [Link]
Variante moderne: MVP
Model-Vizualizare-Prezentator (Model-View-Presenter, MVP)
Stratul de prezentare constă în obiecte de Vizualizare, iar logica
aplicației constă în obiecte de control (Prezentator/Controlor)
Pentru fiecare obiect de vizualizare există un obiect de control
Modelul gestionează accesul la date
104
Florin Leon, Ingineria programarii, [Link]
Arhitectura bazată pe componente
Asamblarea de aplicații din componente
prefabricate
Interfețele trebuie bine definite
Interface Definition Language, IDL
.NET: determinarea interfețelor din implementare
Asigură cuplarea slabă între componente
Diferite tipuri de comunicare între componente
COM, CORBA, JavaBeans
105
Florin Leon, Ingineria programarii, [Link]
Arhitectura orientată pe servicii
Funcționalitățile sunt separate în
unități distincte, numite servicii,
accesibile într-o rețea
Pot fi combinate și reutilizate
Scopul este tot cuplarea slabă
Interfațarea este deosebit de
importantă
Furnizorii de servicii se pot
înregistra la un broker, iar
consumatorii caută serviciile dorite
Mai mulți furnizori pot oferi același
serviciu: calitate, reputație
Servicii web: REST, SOAP
106
Florin Leon, Ingineria programarii, [Link]
Pipeline
Un lanț de elemente de prelucrare în care ieșirea unuia
corespunde cu intrarea următorului
De exemplu: dir | sort | more
Transformările sunt de obicei incrementale
Formatul de date este de obicei simplu, deseori text
Tratarea erorilor este mai dificilă
Utilizări:
Browsere
Aplicații de grafică
Interfețe grafice pentru programe consolă portabile
107
Florin Leon, Ingineria programarii, [Link]
Pipeline
Programare funcțională, F#
|> trimite rezultatul unei funcții următoarei funcții
enumFilesRec
(filterOutPaths ["c:\\Windows";"c:\\ProgramData";"c:\\Program Files"])
(filterExt [".jpg"; ".gif"])
"c:\\Multimedia"
|> [Link] (fun pth -> ([Link] pth, (FileInfo pth).Length))
|> [Link] (fun (_, s) -> ([Link] s) > 1)
|> [Link] (fun (_, sq) -> [for path in sq -> path])
|> [Link] groupEqualFiles
|> [Link] filterOutSingletons
|> [Link] [Link]
|> [Link] (fun lst -> printfn "%A" lst)
[Link] 108
Florin Leon, Ingineria programarii, [Link]
Platforma
engl. “framework”
Pentru o bibliotecă tradițională, programul apelează
funcțiile din bibliotecă
Într-o platformă, apelul codului client este făcut de
către platformă
Exemple:
Platforme multi-agent (de exemplu, JADE sau ActressMAS),
care rulează agenții înregistrați în așa-numitele “containere”
Tensorflow, în sensul că execută un graf computațional (unii
autori îl consideră bibliotecă)
109
Florin Leon, Ingineria programarii, [Link]
Blackboard (tablă)
Presupune existența mai multor „surse de
cunoaștere” specializate pe domenii
diverse
Mai întâi, pe tablă „se scriu” specificațiile
problemei
Fiecare sursă de cunoaștere (specialist)
caută ocazia de a contribui la rezolvarea
problemei
Când cineva scrie pe tablă ceva care
permite unui specialist să contribuie,
acesta scrie la rândul său soluția la
subproblema pe care o poate rezolva
Procesul de adăugare a contribuțiilor pe
tablă continuă până când problema este
rezolvată
110
Florin Leon, Ingineria programarii, [Link]
Blackboard (tablă)
Propusă inițial pentru rezolvarea unor probleme
complexe, insuficient definite
În general, folosită pentru unele aplicații legate de
inteligența artificială, de exemplu:
Sisteme militare de detectare și urmărire a obiectelor (C4ISTAR)
Vizualizare interactivă a datelor de la sateliți (RADARSAT-1)
Recunoașterea optică a caracterelor (Adobe Acrobat Capture)
Interpretarea datelor de la senzori, data fusion
Roboți mobili, planificare, învățare simbolică
111
Florin Leon, Ingineria programarii, [Link]
Șabloane de proiectare
Erich Gamma, Richard Helm, Ralph Johnson,
John Vlissides (“Gang of Four”, GoF): Elements
of Reusable Object-Oriented Software (1994)
112
Florin Leon, Ingineria programarii, [Link]
Clasificare
115
Florin Leon, Ingineria programarii, [Link]
Anti-șabloane
Abstraction inversion Anemic domain model
Input kludge BaseBean
Permite, de exemplu,
Circle-Ellipse problem
code injection (vezi slide-ul următor)
Interface bloat God object
Magic pushbutton Object orgy
Race hazard Poltergeists
Stovepipe system Yo-yo problem
117
Florin Leon, Ingineria programarii, [Link]
Concluzii
Faza de proiectare arată CUM dorim să construim
Se referă la domeniul soluției
Capacitatea de a proiecta bine vine din respectarea principiilor de
proiectare și din experiență
În general, proiectarea corectă asigură o cuplare slabă și o coeziune
puternică
Complexitatea ciclomatică a unui modul este numărul de decizii + 1
Există trei tipuri de șabloane de proiectare, corespunzătoare
nivelurilor de generalitate ale proiectării:
Șabloane arhitecturale (pentru proiectarea arhitecturii)
Șabloane de proiectare (pentru proiectarea modulelor)
Idiomuri (pentru proiectarea detaliată)
118
Florin Leon, Ingineria programarii, [Link]