Ereditarietà, solo per (sviluppatori) adulti

Ereditarietà, solo per (sviluppatori) adulti

Visto l’interesse suscitato dal precedente post sulla relazione di ereditarietà, torno sull’argomento per mettere in risalto ulteriori vincoli da essa imposti.

Lo so, a volte anche le costrizioni possono risultare piacevoli… ed è proprio quello che accade con l’ereditarietà tra classi, certamente vincolante ma così immediata nel realizzare il riuso del codice. E allora, per allontanare questi pensieri impuri dai nostri progetti, recitiamo insieme la seguente preghiera tratta da uno dei testi sacri della programmazione ad oggetti:

Amen! Ma perché i sacerdoti della Gang of four ci invitano a preferire la composizione rispetto all’ereditarietà tra classi? Perché composizione ed ereditarietà sono entrambe una forma di riuso del codice ma l’ereditarietà risulta appunto più vincolante e problematica. Vediamo perché.

  1. Se la classe B estende la classe A, questa relazione è definita nel codice sorgente, pertanto non può cambiare a runtime. Al contrario se B usasse A, B potrebbe referenziare A mediante l’interfaccia I implementata da A. Pertanto a runtime al posto di A ci potrebbe essere un’altra classe di tipo***** I.
  2. Una modifica alla classe A estesa da B può avere ripercussioni indesiderate sul funzionamento di B. Infatti la classe B può accede ai dettagli implementativi di A, violandone l’incapsulamento. In questo caso si parla di riuso di tipo white-box per contrapporlo al riuso di tipo black-box della composizione che invece rispetta l’incapsulamento. Nel caso della composizione tra A che usa B mediante l’interfaccia I, solo una modifica ad I comporterebbe ripercussioni per A.

Dobbiamo quindi bandire l’ereditarietà tra classi dai nostri progetti? Assolutamente no, dobbiamo soltanto usarla con più consapevolezza, tenendo sempre presente che l’ereditarietà conferisce alla classe figlia le seguenti caratteristiche della classe padre:

  1. il tipo
  2. lo stato, ovvero gli attributi
  3. l’implementazione dei suoi metodi

Se non siamo interessati contemporaneamente ai suddetti 3 aspetti allora probabilmente è meglio adottare soluzioni alternative all’ereditarietà. Ad esempio se ci interessa solo il riuso dell’implementazione potremmo indirizzarci verso la composizione, oppure se ci interessa solo il tipo potremmo utilizzare l’ereditarietà delle interfacce o magari l’ereditarietà da una classe astratta, povera di implementazione.

__

***** _ Il tipo di un oggetto è definito come l’insieme delle richieste a cui esso può rispondere, ovvero l’insieme delle firme dei metodi pubblici e quindi l’interfaccia._