PDA

View Full Version : [Generico]Implementazione interfacce


RaouL_BennetH
27-05-2010, 15:58
Ciao a tutti :)

Volevo un vostro parere sul modo più corretto per implementare delle interfacce.

Personalmente ho un dubbio sui seguenti approcci:

Avendo un'interfaccia di esempio:



interface ImplementMe

void MetodoPippo<T>(T t);

void MetodoPluto<T>(T t);

//etc..


//primo approccio: Definisco una sola classe che implementa l'interfaccia

class ClasseProva : ImplementMe

public void MetodoPippo<T>(T t)
{
//blabla
}

public void MetodoPluto<T>(T t)
{
//blabla
}

//esempio di utilizzo:

Oggetto a = new Oggetto();

a.Name = "raoul";
a.Surname = "benneth";

ClasseProva test = new ClasseProva();
test.MetodoPippo(a);
test.MetodoPluto(a);

//secondo approccio: ad ogni oggetto del caso, faccio implementare l'interfaccia

class Farfalla : ImplementMe

class Salmone : ImplementMe

class BuoneLeFarfalleAlSalmone : ImplementMe



Il mio dubbio è che con il secondo approccio, scrivo praticamente gli stessi metodi per N volte.


grazie in anticipo :)

RaouL.

deadlyomen17
27-05-2010, 16:18
Le Interfacce sono molto legate alla programmazione orientata agli oggetti.

In questo contesto, una interfaccia, che è praticamente una classe totalmente astratta che definisce una serie di metodi senza implementarli, è un modo per consentire l'estendibilità, la riusabilità e la manutenibilità del codice.

Non a caso, il concentto di interfaccia è largamente usato nei design pattern.

In realtà i due approcci che dici tu, solo solo uno...ovvero il secondo:
Si crea una interfaccia che definisce una serie di metodi comuni a oggetti diversi. Si creano tante classi concrete che implementano l'interfaccia, tanti quanti sono gli oggetti che si vuole rappresentare.

Questo perchè si fa una interfaccia per consentire di interagire con qualcosa non nota a priori, e che la cui implementazione potrebbe essere addirittura cambiata nel tempo, senza ripercussioni.
Come questo sia possibile, deriva proprio dall'interfaccia.
L'interfaccia definisce una serie di metodi che sono visibili all'esterno, e che sono implementati, in maniera anche decisamente diversa, dalle varie classi concrete che la implementano.
Usando l'interfaccia, si ha un modo univoco per usare uno qualsiasi degli oggetti concreti che la implementano.

Il fatto che in molti casi pratici si da solo una implementazione di una interfaccia, non significa che questa sia inutile, proprio perchè rende il codice estendibile, riusabile e più facile da manutenere.

Ad esempio, una API grafica fornisce un unico oggetto per rappresentare un quadrato. Se in futuro si vorrà estendere l'API, bisognerà riscrivere quell'oggetto, rischiando di renderlo non più compatibile con alcuni utilizzi.
Se invece già in principio, si forniva l'interfaccia al quadrato, e non l'oggetto stesso, nel momento in cui si vuole estenedere l'API, basta creare una nuova classe che implementa questa interfaccia, e per esempio si può lasciare all'utilizzatore la scelta di quale delle due implementazioni di quadrato usare.

PGI-Bis
27-05-2010, 17:46
Le interfacce non hanno nulla a che vedere con la programmazione orientata agli oggetti.

Circa il problema di Raoul_BennetH, nel contesto dell'esempio proposto l'unico criterio che mi sembra sensato è quello dell'economia - il fatto di non scrivere le stesse cose N volte - e l'implementazione unica mi pare di gran lunga avvantaggiata.

E' difficile dire altro perchè quello che concretamente serve di un'interfaccia è il suo tipo, in funzione di collegamento tra due oggetti. Lì però mancano i collegamenti.

RaouL_BennetH
27-05-2010, 18:29
Le interfacce non hanno nulla a che vedere con la programmazione orientata agli oggetti.

Circa il problema di Raoul_BennetH, nel contesto dell'esempio proposto l'unico criterio che mi sembra sensato è quello dell'economia - il fatto di non scrivere le stesse cose N volte - e l'implementazione unica mi pare di gran lunga avvantaggiata.

E' difficile dire altro perchè quello che concretamente serve di un'interfaccia è il suo tipo, in funzione di collegamento tra due oggetti. Lì però mancano i collegamenti.

Ciao :)

Diciamo che intravedo una prima risposta del tipo:

"Non esiste un modo corretto, come al solito, dipende dai casi".

Nel mio caso, non ci sono riferimenti perchè erano solo dei ragionamenti che stavo provando a seguire.

Potrei magari ragionare su un esempio "concreto" ipotizzando al solito la classica situazione legata ad un database:



oggetto Cliente

oggetto Operaio

oggetto Fornitore




etc..

supposto che l'analista abbia fornito un'interfaccia da implementare con questi metodi:


Salva();
Cancella();
Aggiorna();
Elenco();


e che l'abbia progettata così:


Salva<T>(T t);
Cancella<T>(T t);
Aggiorna<T>(T t);
Elenco<T>();


Seguendo il mio ragionamento, io scriverei una semplice classe che implementi l'interfaccia e NON implementerei l'interfaccia per gli oggetti "Cliente, Operaio, Fornitore, etc.." per avere quindi banalmente:



ClasseCheImplementaInterfaccia a = new ClasseCheImplementaInterfaccia();
Operaio o = new Operaio();
Cliente c = new Cliente();
Fornitore f = new Fornitore();

a.Salva(o);
a.Cancella(c);
a.Aggiorna(f);

List<Cliente> listaClienti = a.Elenco<Cliente>();



Si incavolerebbe molto l'analista ? :D

RaouL.

SerMagnus
27-05-2010, 19:05
ovvio che si incavolerebbe non ha senso.
a quel punto bisogna fare una classe base che implementi l'interfaccia e quindi fare derivare da essa le altre classi.

PGI-Bis
27-05-2010, 19:11
Tu applichi un punto di vista "economico" (meno è meglio) in base al quale deduci che la classe unica sia preferibile. E' ineccepibile.

Vediamola da un punto di vista orientato agli oggetti. Cosa cambia?

Primo caso, il codice dice:

classe Cliente
classe Operaio
classe Fornitore
interfaccia Boh
classe BohClass : Boh

L'orientamento agli oggetti dice:

definizione Cliente
definizione Operaio
definizione Fornitore
definizione Boh
definizione BohClass che presuppone Boh

cioè 4 oggetti (Cliente, Operaio, Fornitore, BohClass) e una parte (Boh)

Vediamo l'altra ipotesi. Il codice direbbe:

interfaccia Boh
classe Operaio : Boh
classe Fornitore : Boh
classe Cliente : Boh

in termini OO:

definizione Boh
definizione Operaio che presuppone Boh
definizione Fornitore che presuppone Boh
definizione Cliente che presuppone Boh

3 oggetti (Operaio, Fornitore, Cliente) e una parte (Boh).

E' cambiato qualcosa? No (sorpresa! :D). Nell'orientamento agli oggetti la presenza o l'assenza di un oggetto è sempre irrilevante. E' il principio che fonda la modularità.

Ecco perchè dico che manca qualcosa per poter decidere in un senso o nell'altro. Da un punto di vista orientato agli oggetti. Ripeto, se applichiamo il principio "meno è meglio" allora è meglio la classe unica.

Tieni conto che escludo volutamente questo pezzo:

ClasseCheImplementaInterfaccia a = new ClasseCheImplementaInterfaccia();
Operaio o = new Operaio();
Cliente c = new Cliente();
Fornitore f = new Fornitore();

a.Salva(o);
a.Cancella(c);
a.Aggiorna(f);

List<Cliente> listaClienti = a.Elenco<Cliente>();

Perchè se includiamo questa parte di codice ci troviamo con una definizione che richiede tutte le altre e quindi tutte le altre diventano parti.

nuovoUtente86
27-05-2010, 19:23
ovvio che si incavolerebbe non ha senso.
a quel punto bisogna fare una classe base che implementi l'interfaccia e quindi fare derivare da essa le altre classi.

Non è detto: bisogna valutare come il fantomatico progettista ha inteso l' interfaccia, ovvero se come astrazione di un' entità tabellare o come astrazione di un bridging con il motore di persistenza.
E' normale nel secondo caso (le azioni di storage devono essere slegate dall' oggetto in se) che si faccia riferimento ad un proxy concreto, per mezzo della sua interfaccia.

RaouL_BennetH
28-05-2010, 08:52
PGI-Bis ha scritto:

>cut<

E' cambiato qualcosa? No (sorpresa! ). Nell'orientamento agli oggetti la presenza o l'assenza di un oggetto è sempre irrilevante. E' il principio che fonda la modularità.


Il fatto è che continuo a scontrarmi con quelli che "dovrebbero" essere alcuni dei pilastri OO. Mi riferisco al lavaggio del cervello da "riusa il codice! riusa il codice!". Ok , va bene mi dico, ma scrivere per N oggetti lo stesso identico codice quando mi basta avere (sempre in teoria) un'unico oggetto al quale dare in pasto gli N oggetti non riesco a digerirlo. Inoltre, se per caso l'interfaccia un domani venisse ampliata, dovrei mettere mano sempre agli N oggetti che la implementano anzichè ad un solo oggetto.



SerMagnus ha scritto0:

ovvio che si incavolerebbe non ha senso.
a quel punto bisogna fare una classe base che implementi l'interfaccia e quindi fare derivare da essa le altre classi.

Ecco, e io mi chiedo: perchè?
Riprendo il concetto di sopra:
Se l'interfaccia viene ampliata, nel tuo caso, devo mettere mano sia alla classe base, sia agli oggetti che la ereditano.


nuovoUtente86 ha scritto:

Non è detto: bisogna valutare come il fantomatico progettista ha inteso l' interfaccia, ovvero se come astrazione di un' entità tabellare o come astrazione di un bridging con il motore di persistenza.
E' normale nel secondo caso (le azioni di storage devono essere slegate dall' oggetto in se) che si faccia riferimento ad un proxy concreto, per mezzo della sua interfaccia.

Mi trovo nel secondo caso :)

PGI-Bis
28-05-2010, 14:49
Il fatto è che continuo a scontrarmi con quelli che "dovrebbero" essere alcuni dei pilastri OO. Mi riferisco al lavaggio del cervello da "riusa il codice! riusa il codice!". Ok , va bene mi dico, ma scrivere per N oggetti lo stesso identico codice quando mi basta avere (sempre in teoria) un'unico oggetto al quale dare in pasto gli N oggetti non riesco a digerirlo. Inoltre, se per caso l'interfaccia un domani venisse ampliata, dovrei mettere mano sempre agli N oggetti che la implementano anzichè ad un solo oggetto.

Purtroppo la quantità di dabbenaggini che circolano sull'orientamento agli oggetti è tale che anche le menti più ferree vacillano. Le esposizioni prolungate poi generano vere e proprie sindromi di Stoccolma.

L'orientamento agli oggetti si spiega in tre righe: il codice è fatto di definizioni, alcune di queste sono comprese in altre, quelle che non sono interamente comprese in alcuna altra definizione sono oggetti, le altre sono parti di oggetti. E qui finisce l'orientamento agli oggetti.

Alcune delle cose che si sentono quando si parla di OO sono conseguenze di questo schema, di questo modo di vedere i programmi.

Altre sono stronzate colossali. Afferro il riuso come esempio: che c'entra il riuso con l'orientamento agli oggetti? Una fava. Il riuso c'è anche in assembly. La modularità? C è specificamente progettato per fornirla, che facciamo, diciamo che era OO senza saperlo? No.

Sono cose che c'erano prima e ci sono anche nell'orientamento agli oggetti perchè se non ci fossero l'OO sarebbe da buttare nel cesso.

Ci sono veramente situazioni comiche al riguardo. Autori che si intrallazzano per pagine e pagine cercando di spiegare come mai è meglio scrivere settantamila righe di codice anzichè dieci. E' meglio? No, è che l'autore si è chiaramente perso per strada venti pagine prima e vaga come un disperato cercando di dare un senso a quello che non ce l'ha.

Idem per le interfacce. Attenzione: l'interfaccia dei pattern è l'interfaccia di Java, che è funzionalmente identica ad una classe C++.

Cambierebbe forse qualcosa se al posto dell'interfaccia il tuo analista (che lamentandosi dell'implementazione unica dimostrerebbe di essere analista nel senso dello psicologo più che dell'informatico) ti avesse dato una classe? No, per l'orientamento agli oggetti: è sempre una definizione che tu devi combinare con qualche altra definizione.

Infine, e chiudo la parte generale: fidati del tuo naso. Se ti sembra una stupidaggine è molto probabile che lo sia.

ma scrivere per N oggetti lo stesso identico codice quando mi basta avere (sempre in teoria) un'unico oggetto al quale dare in pasto gli N oggetti non riesco a digerirlo.

E infatti abbiamo visto come NON devi digerirlo: l'orientamento agli oggetti ci dice inequivocabilmente che nel caso che proponi le due soluzioni sono identiche. E c'è il suo bel perchè se scegli quella più economica.

Inoltre, se per caso l'interfaccia un domani venisse ampliata, dovrei mettere mano sempre agli N oggetti che la implementano anzichè ad un solo oggetto.

Questo è esattamente il tipo di ragionamento che da senso all'orientamento agli oggetti: dove mettere le mani se. Questa roba qui che dici tu è quello che ti dice l'analisi OO del codice. Cosa succede se cambio la definizione dell'interfaccia?

Siccome l'interfaccia è una parte, cioè una definizione condivisa da altre definizioni, qualsiasi intervento sull'interfaccia si riflettte su tutte le definizioni a cui essa partecipa.

Una delle "euristiche" dell'orientamento agli oggetti è proprio la minimizzazione delle mutabilità riflesse. Parlo di euristica perchè avere tante o poche di questi "punti di mutazione riflessa" non cambia la natura OO di un programma a meno che esse non riducano il programma ad un unico oggetto. Le minimizzi perchè minore è il loro numero maggiore è la libertà che hai di cambiare il programma in corso d'opera (perchè ottieni un numero maggiore di definizioni che sono oggetti e quindi sono irrilevanti in quanto autonome).

Quindi non è solo sensato "a naso" avere quell'unica classe: è anche sensato dal punto di vista dell'orientamento agli oggetti.

Il problema, e mi riallaccio a quanto diceva nuovoutente86, è che il caso che proponi nella realtà si inserirebbe in un contesto di partenza più ampio. E' possibile che la riduzione fatta con la classe unica nel contesto dell'esempio causi un ampliamento complessivo delle mutazioni riflesse nel contesto reale?

Sorprenderò alcuni dicendo che è qui che entrerebbero in gioco i "pattern" ma non mi dilungo. (e meno male, direte voi :D).

banryu79
28-05-2010, 15:20
Il problema, e mi riallaccio a quanto diceva nuovoutente86, è che il caso che proponi nella realtà si inserirebbe in un contesto di partenza più ampio. E' possibile che la riduzione fatta con la classe unica nel contesto dell'esempio causi un ampliamento complessivo delle mutazioni riflesse nel contesto reale?

Sorprenderò alcuni dicendo che è qui che entrerebbero in gioco i "pattern" ma non mi dilungo. (e meno male, direte voi :D).
Eh no, vecchio volpone: ormai hai lanciato il sasso e non puoi più nascondere la mano... raccontaci tutta la storia (per piacere).
Si fa a volte fatica a trovare del materiale promettente su cui riflettere...

Poi, sempre se sei disponibile, avrei una curiosità. Mi stavo chiedendo: di fronte a un nuovo problema da risolvere, a che cosa è bene stare attenti nel valutare se per risolvere detto problema sia più o meno opportuno usare una prospettiva OO piuttosto che un'altra? (funzionale, procedurale, quello che è...)?

PGI-Bis
28-05-2010, 16:30
Eh no, vecchio volpone: ormai hai lanciato il sasso e non puoi più nascondere la mano... raccontaci tutta la storia (per piacere).
Si fa a volte fatica a trovare del materiale promettente su cui riflettere...

Poi, sempre se sei disponibile, avrei una curiosità. Mi stavo chiedendo: di fronte a un nuovo problema da risolvere, a che cosa è bene stare attenti nel valutare se per risolvere detto problema sia più o meno opportuno usare una prospettiva OO piuttosto che un'altra? (funzionale, procedurale, quello che è...)?

Sarebbe un off topic poco cortese nei confronti dell'autore del thread. Circa la curiosità, se io avessi la risposta avrei il Turing in tasca :D.

RaouL_BennetH
29-05-2010, 10:20
Sarebbe un off topic poco cortese nei confronti dell'autore del thread. Circa la curiosità, se io avessi la risposta avrei il Turing in tasca :D.

Per me non c'è nessun problema :) Anzi !!

cionci
29-05-2010, 11:40
Infine, e chiudo la parte generale: fidati del tuo naso. Se ti sembra una stupidaggine è molto probabile che lo sia.
PGI che parafrasa Fowler e Beck me lo segno :asd:

PGI-Bis
29-05-2010, 16:46
Poichè parlando di programmazione orientata agli oggetti a colpi di mezze risposte a messaggio iniziati su altri argomenti non si può alla fine che rendere un pessimo servizio all'OO ho iniziato a scrivere un testo introduttivo sull'argomento, da infilare nella sezione tutorial.

Non posso garantire che riuscirò a completarlo. Non è la prima volta che inizio a farlo, il problema è che di solito dopo pagina 15 m'incazzo e parto con delle filippiche - di solito indirettamente rivolte ai figuri citati da cionci o alla gang of four, per ragioni diverse ma con pari acrimonia - che certamente non agevolano la comprensione del tema, cioè l'orientamento agli oggetti e non le nefandezze perpetrate in suo nome.

E' anche una questione delicata perchè comunemente la sovraesposizione ad alcuni concetti genera un atteggiamento positivo nei loro confronti.

Così, ad esempio, quando ho scritto che le interfacce non c'entrano nulla con la programmazione orientata agli oggetti, è più che probabile che deadlyomen17 si sia educatamente trattenuto dal rispondere "ma che cacchio dici".

Il fatto è che bisogna scremare un calderone immenso in cui ciascuno ha pensato bene di buttar dentro un po' quello che gli pareva, specialmente chi ha goduto, meritatamente o no, di una certa autorevolezza.

E lo dico avendo presenti i dubbi amletici che ognuno di noi penso abbia riguardo ad alcune questioni.

A quanti di noi è capitato di pensare, guardando un programma OO, che ci sono parti di quel programma che sembrano strutturalmente uguali a quelle che scriveremmo in C? E' strano? Sì. C'è qualcosa che non va? No. C'è un limite "genetico" della programmazione orientata agli oggetti che gli deriva dall'essere applicazione di una prospettiva. E c'è tutto un discorso da fare.

Possiamo davvero darla a bere a qualcuno dicendo che un tipo di programmazione in cui devo usare classi, interfacce, classi astratte, metodi, invocazioni, iniezioni di dipendenza, istanze, pattern e statico e non statico e chi più ne ha più ne metta sia "più facile" di una in cui devo usare variabili, valori e operatori? Non c'è qualcosa che non va? Eccome se c'è. E c'è tutto un discorso da fare.

E ci sono poi le questioni che hanno a che fare con l'orientamento agli oggetti non perchè siano tipiche dell'orientamento agli oggetti ma perchè sono termini generali della programmazione e non vengono abbandonate, perchè sempre programmazione è, ma assorbite e spiegate in termini diversi. Parlo ad esempio del polimorfismo. Questo qui:

int x = 10;
double y = x;

è polimorfismo e il polimorfismo non sta nella programmazione orientata agli oggetti, sta nella teoria dei tipi.

Parliamo di ereditarietà? Apriamo le cataratte? Scopriamo il vaso di pandora, correndo il rischio che saltino fuori degli spilungoni bluastri armati di arco e frecce? Forse non tutti sono abbastanza vetusti per ricordarlo ma se guardate ai programmi OO di una quindicina d'anni fa sembra di vedere la collezione botanica di un seguace di Linneo. Gattus-Domesticus che discende dal Pardus-Pardus che deriva dal Quadupedis-Pelosus e kilometri e kilometri di genealogia. Poi a un certo punto, PAF, saltano fuori e ti dicono: hai derivato per vent'anni? Sei un babbeo, dovevi comporre. E via con la rumba della composizione (che balliamo ancora adesso). Dobbiamo aspettarci che tra cinque anni ci dicano che avendo composto ci siamo infilati nella mota più infima? Be', sì, già adesso c'è qualcuno che mugugna sui dependency injection framework. Quanto è strano se dico che ereditarietà e composizione sono la stessa cosa? E c'è... tutto un discorso da fare.

Insomma, bisogna chiarire tante cose, bisogna rispondere a tante domande, e non è una cosa breve, almeno se vogliamo farlo nell'unico modo ragionevole, ovvero offrendo il fianco alle critiche.

Vediamo cosa salta fuori.

fero86
29-05-2010, 20:44
Poichè parlando di programmazione orientata agli oggetti a colpi di mezze risposte a messaggio iniziati su altri argomenti non si può alla fine che rendere un pessimo servizio all'OO ho iniziato a scrivere un testo introduttivo sull'argomento, da infilare nella sezione tutorial. grazie!!!! :)

RaouL_BennetH
30-05-2010, 00:31
>Cut<


(Il "cut" è solo per far risparmiare un pò di fatica ai criceti di hwupgrade... :D )

Volevo solo dire che, pur non avendo le competenze e l'esperienza tua e di tanti altri utenti, io mi trovo proprio in questa situazione:

Vedo cose talmente complicate che al primo sguardo giustamente mi dico:

"E' complicato per me perchè non conosco ancora i pattern, mvc, ac-dc, il polimorfismo, l'anamorfismo, la morfina, la morfologia, eddy murphy, la gang of four, cool and the gang, test driven (eppure la patente l'ho presa!!) , etc.."

ma ho tanta buona volontà per andare avanti e non limitarmi ad identificare X, Y e metterci il segno in mezzo per ottenere Z.

Scherzi a parte, non avevo idea che il mondo della programmazione fosse così , come dire, "artistico", nel senso che uno stesso problema lo si potesse risolvere in nmila modi diversi.

Ho sempre pensato che dovesse "limitarsi", una volta individuate le variabili, a calcolarne/trattarne il valore, in un modo squallidissimamente matematico :)

banryu79
30-05-2010, 19:37
Sarebbe un off topic poco cortese nei confronti dell'autore del thread. Circa la curiosità, se io avessi la risposta avrei il Turing in tasca :D.
Circa la curiosità: immaginavo non avessi LA risposta; suppongo invece tu abbia delle tue idee e una tua opinione in proposito, e penso non ti stupirà sapere che mi piacerebbe ascoltarle, se ti va di condividerle.


Poichè parlando di programmazione orientata agli oggetti a colpi di mezze risposte a messaggio iniziati su altri argomenti non si può alla fine che rendere un pessimo servizio all'OO ho iniziato a scrivere un testo introduttivo sull'argomento, da infilare nella sezione tutorial.

Magnifica notizia :sbav:

^TiGeRShArK^
31-05-2010, 01:14
:mbe:
Ma solo io vedo la cosa più semplice nell'implementare l'interfaccia in un abstract class padre di tutte le altre e far ereditare i figli da quella classe? :mbe:
In questo modo puoi usare tranquillamente quei metodi senza riscriverli per tutti gli oggetti figli, e, in caso in futuro ti servisse qualche funzionalità diversa in quei metodi per determinati oggetti, basterebbe applicare il più classico degli strategy pattern facendo un semplice override solo di quei metodi per cui il codice generale che hai scritto non va più bene in quel caso particolare.
Il tutto senza rompere il contratto specificato dall'interfaccia e senza far incazzare l'analista (brrrr.... mi vengono i brividi a pensare che in italia c'è ancora la suddivisione tra analista e programmatore. :doh: )

Kralizek
31-05-2010, 08:32
mica solo in Italia, ho seguito da poco un master tenuto da Juval Lowy (mica il primo fesso, per intenderci) e lui era il primo a fare commenti classisti tra l'architetto ed il programmatore...

certo ci sono da tenere in considerazione le dovute distinzioni, ma la base é che l'architetto/analista é diverso dal programmatore, per incarichi e competenze.