Newsgroup: it.comp.dotnet
Titolo: il perché delle interfacce

Si legge da MSDN "Un'interfaccia è simile a una classe base astratta: 
qualsiasi tipo non astratto che eredita l'interfaccia deve implementarne 
tutti i relativi membri."
Quindi se io scrivo ad esempio diciamo 10 classi che derivano da 
interface, devo implementare per ognuna di queste classi i metodi 
dell'interfaccia.
Se questa mia interpretazione è corretta non ne comprendo l'utilità, ma 
senz'altro non è così...
Il perché usare le interfacce mi è oscuro...
Chiedo lumi su questo, grazie.


Guarda ad un'interfaccia come un contratto.
In un interfaccia descrivi cosa offre e come manipolare gli oggetti.
IAnimale potrebbe descrivere:
- la proprietà Zampe di tipo int che dovrà restituire il numero di 
zampe dell'animale
- la proprietà Colore
- il metodo Cammina che andrà a sottrarre un certo numero di calorie
Le classi Uomo e Pantera implementeranno quest'interfaccia perché hanno 
quelle caratteristiche ma la loro implementazione sarà differente.
Il vantaggio dell'interfaccia è che una classe puoi implementarne più 
di una (multiple inheritance) mentre una classe non può derivare da più 
di una classe base (single inheritance).
Il vantaggio della classe astratta base è che può provvedere ad 
un'implementazione comune a più classi che la deriveranno. In quanto 
astratta, non può essere istanziata e andrà derivata. Le classi 
derivate potranno usare le implementazioni base oppure riscriverle 
totalmente o chiamarle per poi fare altre cose.
Cerca prima di inquadrare il problema generale. La sintassi poi viene 
da sé in quanto è molto più semplice rispetto a C++.
-- 
Raffaele Rialdi  
http://www.iamraf.net
Weblog: 
http://blogs.ugidotnet.org/raffaele
Microsoft MVP profile 
https://mvp.support.microsoft.com/profile/raffaele
UGIdotNET - 
http://www.ugidotnet.org/

 tutti i relativi membri."
A corredo della gia' ottima risposta di Raf aggiungo che una classe
astratta non e' poi cosi' simile ad un interfaccia: una classe
astratta puo' implementare proprieta', metodi e avere membri privati,
cioe' puo' fare piu' o meno tutto quello che puo' fare una classe
concreta se non che non puo' essere istanziata e ti impone di usare
classi derivate per poter istanziare oggetti. Di solito una classe
astratta implementa tutta la logica generale/comune ed espone uno o
piu' membri appunto astratti che sono poi gli unici a cui la classe
derivata deve dare una implementazione concreta.
-LV


In generale, una cosa e' una gerarchia di classi, dove la classe base
spesso e' astratta, e l'uso di interfaccie per simulare
l'ereditarieta' multipla e' piuttosto un trucco un po' "sporco". Altra
cosa sono le interfaccie, il cui uso primario e' di essere esposte al
livello di boundary fra componente diversi di un sistema.
-LV

 l'ereditarieta' multipla e' piuttosto un trucco un po' "sporco".
a tal proposito, in C#, l'ereditarietà è identica a quella 
nativa del C++ ?
ciao
Soviet


 in C#, l'ereditarietà è identica a quella nativa del C++ ?
Ovviamente no: tanto per dirne una, appunto in C# (o in VB) non hai
ereditarieta' multipla.
Comunque penso che non ci sia neanche in C++/CLI, visto che ci sono
tutte le restrizioni necessarie a rendere il codice appunto conforme
alla specifica CLI.
-LV

 a tal proposito, in C#, l'ereditarietà è identica a quella nativa del C++ ?
A parte il concetto base che è identico in ogni linguaggio oo, ci sono 
significative differenze. Tanto per fare un esempio in C# mancano 
l'ereditarietà multipla per le classi e la visibilità (non esiste 
ereditarietà privata).


 alla specifica CLI.
Confermo e proprio per il motivo che hai detto



mi aggiungo in coda....
un'interfaccia definisce anche un "tipo", quindi puoi passare qualunque 
oggetto la implementi laddove ci si aspetta un "tipo" di interfaccia in 
particolare, a prescindere da come i vari oggetti implementano i metodi 
dell' interfaccia.

ho creato due  interfacce
IFileIo e IQueryBase due classi e le relative implementazioni nelle 
classi FileIO e QueryBase.
Adesso creo una classe così:
  class Installa:IFileIO,IQueryBase
     {
         public FileIO fio = new FileIO();
         public XQueryBase xq = new XQueryBase();
         public void CreaDataBase()
         {
         }
     }
alla compilazione mi da errori elencandomi per tutti metodi usati
Errore	1	'CoGe.Installa' non implementa il membro di interfaccia 
'CoGE.IQueryBase.GetColumn<T>(string)'	D:\Visual Studio 
2010\Projects\CoGE\Installa.cs	
Cosa vuol dire questo che anche all'interno della classe installa devo 
reimplemantare i metodi?
Non mi sembra coerente.....
L'esempio del codice è quello riportato (con le trasposizioni del case) 
è tratto dalla rete.
Grazie Ferradini

 Non mi sembra coerente
coerente con cosa?


scusa mi è partita la risposta senza volerlo:
la coerenza c'è tutta perché un'interfaccia introduce un polimorfismo di 
comportamento nelle classi, per cui si presuppone che ogni classe debba 
"ridefinire" il proprio specifico comportamento.
Ciao.

 classi FileIO e QueryBase.
forse qui inizia il fraintendimento: le classi FileIO e QueryBase 
implementano le interfacce IFileIo e IQueryBase, ma non sono _necessarie_.
Tutto quello che tu imponi scrivendo delle interfacce è che chi le 
implementa, cioè _sia_ FileIO e QueryBase, _sia_ Installa, _devono_ 
fornire un'implementazione dei metodi che hai _dichiarato_ nelle 
interfacce: è appunto un contratto.
Cioè tu mi dici:
"io classe Installa implemento IFileIO e IQueryBase"
e io capisco:
"allora per contratto _devi_ avere un'implementazione di 
GetColumn<T>(string), etc etc..."
Quello che forse volevi tu era una classe astratta, che appunto ti 
consente di dichiarare metodi astratti (senza corpo, tipo semplice 
dichiarazione) da implementare _obbligatioramente_ nelle classi 
derivate, ma anche metodi con implementazione, che possono essere 
semplicemente richiamati o sovrascritti (override) da una classe derivata.
Nel tuo caso FileIO, QueryBase e Installa sono allo stesso identico 
"livello gerarchico" anche se detta così è una forzatura, ma è per 
capirci che Installa non eredita nulla da FileIO, QueryBase.

Allora chiedo (confessando nel contempo la mia profonda ignoranza del 
c#):  per derivare Installa da due classi IFileIO e IQueryBase, come 
mannaggia ......  si fa?
Può Installa usufruire dei metodi delle due classi FileIO e QueryBase?
Ovviamente senza reimplementare GetColumn<T>(string) e le altre?
Se si chiedo cortesemente come si fa, se non è possibile evidentemente 
la logica del C# sfugge dalle mie conoscenza.


Non è un problema di c# ma di OOP.
Non mi è chiaro il dominio che stai progettando, ma così a orecchio non 
penso che una classe Installa possa derivare da una classe FileIO e una 
classe QueryBase. Se fosse possibile, Installa dovrebbe essere 
contemporaneamente "un tipo di" FileIO e "un  tipo di" QueryBase...
se anche fosse possibile, in .Net non lo puoi fare perché il framework 
non consente l'ereditarietà multipla!
Sempre a orecchio (quindi potrei sbagliare perché non so che stai 
astraendo...), credo che la tua classe Installa, debba usare 2 
interfacce e non 2 classi... anche se sbaglio, però, in c# al massimo 
potresti derivare da una sola delle 2 e l'altra la dovresti sempre 
implementare come interfaccia (e quindi, si! dovresti riscriverti i 
metodi in base al "comportamento" di Installa)...
Ciao

 la logica del C# sfugge dalle mie conoscenza.
Come gia' detto, in .Net non hai ereditarieta' multipla. Inoltre sono
davvero rari i casi in cui l'ereditarieta' multipla e' davvero
necessaria, mentre piu' spesso indica complicazioni inutili al livello
di disegno delle classi.
Cio' detto, in questo caso specifico un suggerimento piu' o meno
scontato e' che la classe Installa sia piuttosto un composizione (*)
sopra alle due classi FileIO e QueryBase. Se quindi, nel caso piu'
semplice, esponi le due classi in questione direttamente come
proprieta' della classe contenitore, un client puo' fare direttamente
cose del tipo installa.FileIO.MetodoX(), ecc. Altrimenti, se occorre
che le due classi contenute siano nascoste al client, la classe
contenitore dovra' necessariamente implementare dei metodi al minimo
con la logica per inoltrare/smistare le chiamate.
In ogni caso, l'effettiva necessita' di esporre interfacce e su quali
classi sarebbe un po' tutta da rivedere: ricorda che le interfaccia in
generale vanno usate solo al livello di boundary dei componenti:
quindi definisci le interfacce tenendo conto di cosa un eventuale
(codice) client deve vedere.
(*) E' la relazione "has a": 
http://en.wikipedia.org/wiki/Object_composition
-LV

Vedo che ci stiamo avvicinando al nocciolo del problema.
In effetti le due classi devono essere utilizzate in Installa, ma 
concettualmente non hanno niente a che vedere con installa.
Potrei scrivere qualcosa del tipo
Class Installa {
FileIO fio = new FileIO;
QueryBase xq = new QueryBase;
}
e cosi via per ogni altro metodo che eventualmente andrei ad utilizzare 
per Installa.
Oppure potrei scrivere qualcosa del tipo class QueryBase:FileIO
e poi Installa:QueryBase, cosi Installa usufruisce sia di FileIO che di 
QueryBase. Ma non mi sembra un gran che come soluzione, anche perchè non 
permette di ereditare solo dalla catena QueryBase: FileIO
Un anno fa chiesi a un newsgroup come fare e mi si rispose di rivolgermi 
a una eredita multipla (simulata in qualche modo.
Da qui sono passate attraverso ripetute prove capendone sempre di meno e 
senza nessun risultato.
Morale della favola: sono ancora al punto di partenza e l'unica via che 
riesco a praticare è quella soprastante, cioè
Class Installa {
FileIO fio = new FileIO;
QueryBase xq = new QueryBase;
}

 }
e secondo me è la migliore, perché rispecchia il fatto che per 
"Installare" *usi* i servizi di FileIO e QueryBase, mentre non è vero 
che Installa *estende* le funzionalità di un FileIO e QueryBase fornendo 
un servizio più specializzato: Installa (immagino) è una classe per fare 
un'operazione "una tantum", mentre FileIO e QueryBase (immagino) sono 
delle classi "toolbox".
Al limite, se proprio tu volessi, potresti estrarre da FileIO e 
QueryBase un insieme comune di funzionalità che ti servono e farci una 
classe "InstallaToolBox" da ereditare, ma come detto sopra non mi suona 
come la cosa più corretta a livello di architettura.