Post on 18-Oct-2020
POO
Proiectarea de clase
D. Lucanu POO – Proiectarea de clase 2
Cuprins
principiul inchis-deschis
principiul substituirii
principiul de inversare a dependentelor
sabloane de proiectare (software design patterns)
• clase cu o singura instanta (Singleton)
• fabrica de obiecte (Abstract Object Factory)
D. Lucanu POO – Proiectarea de clase 3
Principiul “inchis-deschis”
“Entitatile software (module, clase, functii etc.) trebuie sa
fie deschise la extensii si inchise la modificare”
(Bertrand Meyer, 1988)
“deschis la extensii” = comportarea modulului poate fi
extinsa pentru a satisface noile cerinte
“inchis la modificare” = nu este permisa modificarea
codului sursa
Principiul “inchis-deschis” : exemplu
D. Lucanu POO – Proiectarea de clase 4
citeste()
Figura
citeste()
Segment
citeste()
Cerc
incarca()
ContainerFig
1 *
D. Lucanu POO – Proiectarea de clase 5
Principiul “inchis-deschis”: neconformare
void ContainerFig::incarca(std::ifstream& inp)
{
while (inp)
{
int tipFig; Figura* pfig;
inp >> tipFig;
switch (tipFig)
{
case SEGMID:
...
case CERCID:
...
}
}
}
O solutie: Fabrica de figuri (… un pic mai tarziu)
D. Lucanu POO – Proiectarea de clase 6
Principiul “inchis-deschis”: conventii
Declara toate datele membre private
• altfel:
• Schimbarea tipului datei implica schimbarea
functiilor care o utilizeaza
• in plus, nu avem incapsulare
Fara variabile globale
• O alternativa: clase cu membri statici
D. Lucanu POO – Proiectarea de clase 7
Principiul substituirii
[A se vedea si prezentarea privind Principiile POO]
“Functiile care utilizeaza pointeri sau referinte la clasa de
baza trebuie sa fie apte sa utilizeze obiecte ale claselor
derivate fara sa le cunoasca”
care parafrazeaza
“Daca pentru fiecare obiect o de tip S exista un obiect o’
de tip T astfel incat, pentru toate programele P definite in
termenii lui T, comportarea lui P nu se schimba daca
substituim o cu o’, atunci S este un subtip al lui T.”
(Barbara Liskov, 1988)
D. Lucanu POO – Proiectarea de clase 8
Principiul substituirii: neconformare
merge()
Autovehicul
merge()
AutovehiculCuGabaritDepasit
dubleazaLatime()
Dreptunghi
dubleazaLatime()
Patrat
D. Lucanu POO – Proiectarea de clase 9
Principiul substituirii: neconformare
class Dreptunghi {
public:
virtual void dubleazaLatime();
virtual int aria();
protected:
int latime, lungime;
}
Daca dr.aria = d, dupa dr.dubleazaLatime(); avem dr.aria = 2*d
class Patrat : public Dreptunghi {
public:
virtual void dubleazaLatime(int);
virtual int aria();
}
Daca pat.aria = p, dupa pat.dubleazaLatime(); avem pat.aria = 4*p
D. Lucanu POO – Proiectarea de clase 10
Principiul substituirii: neconformare
void Drepunghi::dubleazaLatime() {
latime *= 2;
}
void Patrat::dubleazaLatime() {
latime *= 2;
lungime *= 2;
}
void g(Dreptunghi& d) {
int aria1 = d.aria();
d.dubleazaLatime();
assert(d.aria() = 2*aria1);
}
D. Lucanu POO – Proiectarea de clase 11
Proiectare prin contract
Obligatii Beneficii
Client trebuie sa asigure poate beneficia de pe
preconditia urma postconditiei
Prestator trebuie sa asigure poate presupune
Servicii postconditia preconditia
Contractele in mostenire
• precizeaza pre- si post-conditiile pentu fiecare metoda
• “cand se redefineste o metoda intr-o clasa derivata,
preconditia se inlocuieste prin o conditie mai slaba iar
postconditia prin una mai tare.” (Bertrand Mayer,
1988)
D. Lucanu POO – Proiectarea de clase 12
Proiectare prin contract
...A::f(...)
{
//requires p1 (prec.)
//ensures q1 (post.)
...
}
...B::f(...)
{
//requires p2 (prec.)
//ensures q2 (post.)
...
}
f()
A
f()
B
D. Lucanu POO – Proiectarea de clase 13
Proiectare prin contract
A a; B b;
b poate fi utilizat oriunde a este utilizat
• b.f() poate fi apelata in orice stare in care a.f() este
apelata, deci b.f() necesita (requires) o conditie mai
slaba
• daca p1, atunci p2
• starile produse de b.f() satisfac proprietatile
satisfacute de starile corespunzatoare produse de
a.f(), deci b.f() asigura (ensures) o conditie mai tare
decat a.f()
• daca q2, atunci q1
D. Lucanu POO – Proiectarea de clase 14
Proiectare prin contract
void Dreptunghi::dubleazaLatime(){
//requires: true
//ensures: latime = 2 * old(latime) /\
// lungime = old(lungime)
latime *= 2;
}
void Patrat::dubleazaLatime(){
//requires: lungime = latime
//ensures: latime = 2 * old(latime) /\
// lungime = latime
latime *= 2;
lungime *= 2;
}
D. Lucanu POO – Proiectarea de clase 15
Principiul substituirii
//requires: true
//ensures: latime = 2 * old(latime)
//requires: lungime = latime
//ensures: latime = 2 * old(latime)) /\
// lungime = latime
dubleazaLatime()
Dreptunghi
dubleazaLatime()
Patrat
D. Lucanu POO – Proiectarea de clase 16
Principiul de inversare a dependentelor
A. “Modulele de nivel inalt nu trebuie sa depinda de
modulele de nivel jos. Amandoua trebuie sa depinda de
abstractii.”
B. “Abstractiile nu trebuie sa depinda de detalii. Detaliile
trebuie sa depinda de abstractii.”
programele OO bine proiectate inverseaza dependenta
structurala de la metoda procedurala traditionala
• metoda procedurala: o procedura de nivel inalt
apeleaza o procedura de nivel jos, deci depinde de ea
D. Lucanu POO – Proiectarea de clase 17
Principiul de inversare a dependentelor
: Top Package::Buton : Top Package::Lampa
aprinde()
stinge()
ButonLampa 11
D. Lucanu POO – Proiectarea de clase 18
Principiul de inversare a dependentelor
class Lampa {
public:
void aprinde();
void stinge();
}
class Buton {
public:
Buton(Lampa& plampa) : lampa(&plampa) {}
void detecteaza();
private:
Lampa *lampa;
}
D. Lucanu POO – Proiectarea de clase 19
Principiul de inversare a dependentelor
void Buton::detecteaza()
{
bool stare = getStareFizica();
if (stare)
lampa->aprinde();
else
lampa->stinge();
}
D. Lucanu POO – Proiectarea de clase 20
Principiul de inversare a dependentelor
ButonImplementareLampa
11ClientButon Buton
D. Lucanu POO – Proiectarea de clase 21
Principiul de inversare a dependentelor
class ClientButon {
public:
virtual void aprinde() = 0;
virtual void stinge() = 0;
}
class Buton {
public:
Buton(ClientButon& pclient) : client(&pclient) {}
void detecteaza();
virtual bool getStare() = 0;
private:
ClientButon *client;
}
D. Lucanu POO – Proiectarea de clase 22
Principiul de inversare a dependentelor
class Lampa : public ClientButon {
public:
virtual void aprinde();
virtual void stinge();
}
class ButonImpl : Buton {
public:
ButonImpl(ClientButon& pclient) : client(&pclient)
{}
virtual bool getStare();
private:
}