Newsgroup: it.comp.lang.c++
Titolo: 2 Filosofie di ereditarietà, quando usarle ?

Followup-To: it.comp.lang.c++
Filosofie di ereditarietà:
Ultimamente un collega mi ha fatto notare una cosa su cui non mi ero mai soffermato a riflettere:
L'opportunità di utilizzare il meccanismo dell'ereditarietà secondo 2 filosofie diverse tra loro.
1) Filosofia " additiva"
Mano a mano che specializzo un concetto aggiungo membri
class A
	x
	y()
 
class B : A
	z
	k()
 
2) Filosofia "riempitiva"
Definisco un interfaccia che raggruppi tutte le feature della gerarchia.
Nell'implementare la gerarchia utilizzo membri fantoccio per quelle classi
in cui le feauture non hanno ancora "senso".
Tali membri (solo metodi?) dovranno comunque ritornare valori "sensati".  
interface I
	x
	z
	y()
	k()
 
class A : I
	x
	z dummy
	y()
	k() dummy
class B : A
	z
	k()
Chi conviene:
Personalmente ho sempre ragionato secondo quella "additiva", ma effettivamente, mi sembra che 
con la "riempitiva" e una scelta oculata dell'implementazione dei membri fantoccio si possa avere
maggior flessibilità nella parte di codice che utilizza I, A, B. Se non ti interessa distinguere tra
A e B usi I, altrimenti no. Con la "riempitiva" manipoli tutti gli oggetti A e B come degli I senza
dover distinguere esplicitamente il tipo.
(nota:  spesso in C++ non vuoi usare la RTTI e devi implementare metodo "cosa sono?").
Con la "additiva" nel caso si debba manipolare una collezione d'istanze di A e B (implementata
magari come un Bag di A) occorre testare il tipo per essere sicuri di poter utilizzare le features
di B.
Naturalmente con la "riempitiva"  le features appaiono tutte in una volta, quindi documentare/capire
l'interface I può essere complesso, ma è anche vero che hai tutto in un unico punto/concetto.
Boh... secondo voi come stanno le cose ? Quando una è meglio dell'altra ?
Queste due filosofie/design pattern" possono essere ricondotte a qualche altro ?
Grazie.
PS: Spero di non aver fatto casini con crosspost e followup...
#######################################################################
email:     remove "NoNoNo"
           rimuovi "NoNoNo"
homepage:  
http://i.am/ovale
#######################################################################

Il vero problema e' che secondo me stai guardando l'ereditarieta' dal
verso sbagliato. In generale considerare una sottoclasse come
un'estensione di una superclasse e' fuorviante: e' piuttosto la
superclasse che costituisce un'astrazione della sottoclasse, anzi
possibilmente degli elementi comuni di classi diverse, ed il suo scopo
e' fornire un'interfaccia che esuli da un insieme di dettagli specifici.
In questo senso quella che tu chiami "filosofia riempitiva" e'
perniciosa: perche' estendere in modo arbitrario e innaturale
un'interfaccia, quando il suo scopo e' proprio astrarla da *quei*
dettagli specifici?
Il problema sara' piuttosto mettere a disposizione correttamente le
diverse interfacce disponibili in base al contesto.
Alla base del discorso sta la considerazione che nella maggior parte dei
casi e' opportuno evitare di specializzare classi gia' esistenti, a meno
che queste non siano disegnate apposta ed il comportamento atteso dalle
funzioni membro virtuali che si intende sostituire non sia specificato
in dettaglio. Disegnare *bene* una classe da estendere non e' banale.
Ciao,
Nicola

 in dettaglio. Disegnare *bene* una classe da estendere non e' banale.
Una classe va estesa per derivazione solo nel senso che la si specializza
rispetto all'astrazione della sua base. La classe derivata quindi rappresenta
una astrazione piu' concreta di quella della classe base. In una astrazione piu'
concreta o specializzata e' possibile che esistano operazioni che non avevano
senso nella classe piu' astratta. In tal caso l'interfccia della classe derivata
puo' essere piu' estesa.
Andrea Ferro
---------
Brainbench C++ Master. Scored higher than 97% of previous takers
Scores: Overall 4.46, Conceptual 5.0, Problem-Solving 5.0
More info 
http://www.brainbench.com/transcript.jsp?pid=2522556

 classe derivata puo' essere piu' estesa.
Questo va bene in teoria. In pratica pero' l'esperienza insegna che la
specializzazione e' un costrutto da prendere con le pinze, perche' da
una parte provoca una interdipendenza forte e "pubblica" tra due classi,
dall'altra fa leva su un'interfaccia che spesso non e' stata pensata con
sufficiente accuratezza. Questo era il senso della mia affermazione
precedente.
Ciao,
Nicola

 precedente.
In questo senso sono d'accordo. Ma nota che il fatto che la classe base non sia
pensata per essere estesa e' un problema di design della classe base. In Java e'
possibile avere un enforce da parte del linguaggio (final). Ma il problema e'
solo spostato: se qualcuno scopre una possibile derivazione che e' valida
nonostante la classe non sia specificatamente disegnata per questo, final e'
piu' un impiccio che un vantaggio!
--


 piu' un impiccio che un vantaggio!
E' l'idea che qualcun altro possa saperne di piu' su una classe di
quanto non ne sapeva il suo autore originale nel momento in cui l'ha
scritta che e' sbagliato nel fondo.
Mi stai convincendo che lo studio dell'OO "pura" e' un'altra cosa da
disimparare quando si programma in C++. Altro che C!
Ciao,
Nicola

 disimparare quando si programma in C++. Altro che C!
Per essere sincero la cosa che si fa fatica a disimparare e' il fatto che
l'estensione di una interfaccia debba avvenire sempre e solo per derivazione e
mai per modifica. Questa rigidezza delle librerie C++ e' la cosa piu' difficile
da tener presente. Persino piu' del fatto che il C++ non sia a tipizzazione
dinamica.
Tra parentesi questo e' proprio il motivo che induce a sviluppare in C++ usando
i generici o separando nettamente interfacce da implementazioni (almeno in fase
di analisi e design ad alto livello).


 di analisi e design ad alto livello).
Direi che e' un circolo vizioso (virtuoso?). L'esistenza della
caratteristica di base spinge a trarne il massimo vantaggio possibile
estremizzandone l'uso.
Ciao,
Nicola

 estremizzandone l'uso.
Piu' vizioso che virtuoso! Infatti non sono d'accordo sul fatto che se ne tragga
il massimo vantaggio possibile. Non ho praticamente mai visto una libreria o un
framework C++ che non faccia assunzioni a priori sulla costruzione di istanze.
Se ti va bene ti permette di ridefinire la classe concreta di ALCUNE istanze
direttamente nel dominio dello specifico problema che il framework risolve (per
esempio la classe document).


 esempio la classe document).
Il problema e' che STL a parte si sta cominciando solo ora a scrivere
librerie in C++ moderno.
Ciao,
Nicola

 librerie in C++ moderno.
Il che la dice lunga sulla diatriba imparare il C++/imparare a progettare il SW.


 il SW.
Imparare a progettare bene il software e' talmente piu' difficile che
imparare un linguaggio di programmazione che al confronto la differenza
di difficolta' nell'imparare un linguaggio piuttosto che un altro
sparisce.
Ciao,
Nicola