Introducere Interface

Delegarea (delegation) sau
Cand sa nu folosim mostenirea

Definitie

Delegarea reprezinta o modalitate de a extinde si reutiliza functiunile unei clase C1 prin crearea unei clase C2 cu functiuni noi si care utilizeaza instante ale clasei C1 pentru a indeplini functiunile originale.

Context

Extinderea si reutilizarea functiunilor unei clase se obisnuieste sa se realizeze adesea prin mostenire. Mostenirea este utila pentru a modela relatii de genul "este-un-fel-de" ("is-a-kind-of"). Aceste relatii sunt statice in raport cu timpul. De aceea, nu in toate situatiile este adecvata aplicarea mostenirii.
Delegarea este o modalitate mai generala pentru extinderea comportamentului unei clase, care implica apelul metodelor clasei respective in loc de mostenirea lor. Delegarea se preteaza la modelarea relatiilor de tip "este-un-rol-jucat-de" ("is-a-role-played-by").
Exemplu: in cadrul unui sistem de evidenta a personalului unei universitati avem de a face cu roluri ca: student, cadru didactic, personal TESA. O posibilitate de a reprezenta acest ansamblu ar fi sa se creeze o ierarhie de forma:

Problema apare cand aceeasi persoana poate indeplini mai multe roluri, sau chiar combinatii de roluri la momente de timp diferite (de exemplu, un preparator este si student si cadru didactic sau un cadru TESA poate fi si student). Deoarece relatia de mostenire este statica, utilizand mostenirea avem nevoie de mai multe obiecte sau de mai multe subclase pentru reprezentarea aceleiasi persoane, corespunzatoare fiecarui rol sau combinatie de roluri pe care le joaca.
Utilizand delegarea, eliminam problema legata de numarul subclaselor:

O alta situatie in care se recomanda utilizarea delegarii o reprezinta definirea unor clase care modeleaza colectii de obiecte, asa ca in secventa de mai jos:
 
class Colectie {
        Secventa *seq;
    public:
        void adauga(Obiect *unObiect) { seq -> add(unObiect); }
    //. . .
};

Aici clasa Secventa poate fi o clasa de uz general care implementeaza o structura gen vector, lista etc. Ideea este ca, in loc sa derivam clasa Colectie din Secventa, aplicam delegarea (v. paragraful "Motivatii").

Motivatii
In practica proiectarii software se intalnesc adesea utilizari inadecvate ale mostenirii, care au fost categorisite ca "anti-sabloane". Printre acestea cele mai frecvente sunt:

Ca sa ne dam seama cand suntem pe cale sa aplicam mostenirea in mod nepotrivit, iata doua dintre criteriile pe care le putem aplica:


Solutie

Delegarea reprezinta un mod de a reutiliza si extinde comportamentul unei clase. Ea se realizeaza scriind o noua clasa (delegatorul) care incorporeaza functionalitatea clasei originale (delegatul) prin intermediul unei instante a acesteia din urma:

Delegarea este mai generala decat mostenirea. Orice extensie adusa unei clase prin mostenire se poate realiza si prin delegare.
 

Consecinte

Principalul dezavantaj al delegarii este gradul mai scazut de structurare fata de mostenire. Relatiile dintre clase modelate cu ajutorul delegarii sunt mai putin clare. In acest sens exista cateva cai de ameliorare a lucrurilor:


Implementare

Presupune obtinerea de catre clasa delegator a unei referinte spre o instanta a clasei delegat si apelarea metodelor acesteia:
 

class Delegator {
    Delegat *p;
    //. . .
    public:
        void metodaDelegator {
            //. . .
            p->metodaDelegat();
            //. . .
        }
};

Obs: initializarea membrului p se poate face prin constructorul clasei Delegator si/sau prin alte functii membru ale acesteia.
 


Tema

    Se cere sa se defineasca o clasa Depozit care sa modeleze functionarea unui depozit comercial de marfuri (intrari de marfa, vanzari, afisarea unui inventar). Clasa va fi constituita ca o colectie de obiecte caracterizate prin nume, cod unic (care identifica in mod univoc diferitele produse), pret si cantitate. Comportamentul clasei Depozit se va obtine aplicand delegarea asupra unei clase "de uz general", gen Vector sau Lista, folosind operatiile specifice de adaugare/eliminare de elemente, respectiv parcurgere. Clasa delegat va fi definita tot in cadrul temei sau va fi preluata, daca e posibil, din biblioteca atasata mediului de programare folosit.

Introducere Interface