View Full Version : [C++] Quando usare una classe astratta ?
Sera,
stò facendo vari test con il C++ per "riprendere" l'ottica OOP.
In questo momento stavo pensando di semplificare l'utilizzo delle varie funzioni utilizzando una sola classe generale che a sua volta quindi inizializza tra i propri elementi private le altre classi.
Mi è sorto però un dubbio.
Anzichè scrivere nella classe, sempre qualcosa come:
//definizione e dichiarazione della classe AltraClasse;
class TestMe
{
private:
AltraClasse* riferimento;
public:
TestMe();
~TestMe();
};
}
TestMe::TestMe
{
this->riferimento = new AltraClasse;
}
TestMe::~TestMe
{
delete this->riferimento;
}
Ho volutamente tralasciato la dichiarazione e definizione della classe AltraClasse perchè priva di interesse.
La questione è: mi converrebbe, invece che fare come sopra, dichiarare AltraClasse come astratta (con le funzioni virtual) e quindi fare ereditare dalla classe TestMe i metodi astratti di AltraClasse ?
In cosa consisterebbe la convenienza?
Spero di essere stato chiaro :)
La classe TestMe (nome di pura fantasia) gestisce interamente le altre classi (quella per l'eccezione degli errori, etc...).
Quindi, quando usare (praticamente parlando) la classe astratta? Sempre ogni qual volta non la uso nel programma direttamente, ma ne uso i metodi solo tramite altre classi ?
Grazie mille.
Una classe astratta ha senso quando hai bisogno di una classe più generica che non istanzierai mai in cui metti la base, ma poi definisci più classe figlie specializzate dove metti tutto.
Stai cercando di riprendere in mano l'OOP eppure nel tuo intero post non c'è una sola volta la parola "oggetto". C'è qualcosa che non va.
Non c'è alcuna convenienza nell'uso di una classe astratta rispetto ad un modulo piuttostoche ad una funzione.
Tutto quello che c'è sono gli oggetti che compongono il tuo sistema: è dalle caratteristiche di questi oggetti che ricavi la necessità di usare una classe totalmente o parzialmente definita o di non usarla affatto.
Quando usi una classe? Be', quando nel sistema hai una pluralità di oggetti che si comportano tutti quanti nello stesso modo.
Dunque domanda numero 1: nel tuo sistema hai una pluralità di oggetti che si comportano tutti quanti nel modo definito in AltraClasse? Se sì, AltraClasse è una classe, altrimenti, in C++, è un modulo.
Lo stesso vale per TestMe: pluralità -> classe, altrimenti modulo.
E veniamo all'astrazione. TestMe dev'essere una classe astratta? Be', bisogna capire cosa diamine sia quest'astrazione, no?
Abbiamo detto che una classe è la rappresentazione di una pluralità di oggetti i quali si comportano allo stesso modo. Ho diecimila oggetti che hanno un nome e un cognome - o due, pluralità è più di uno. La manifestazione di quel nome e cognome è il comportamento che tutti gli oggetti di tipo X condivide.
Per le classi astratte il principio è identico: più d'un oggetto ha uno stesso "set" di comportamenti. Tra questi comportamenti che tutti quanti gli oggetti di tipo X possiedono almeno uno consiste nella definizione di un comportamento. Ho un nome, ho un cognome e devo dire come faccio a camminare.
Che significa dire AltraClasse è una classe il cui metod abc è astratto? Esattamente come succederebbe per una classe "normale" significa dire che c'è più di un oggetto che si comporta come descritto in AltraClasse. Siccome AltraClasse dice che tra le sue caratteristiche c'è la definizione di un comportamento, ogni oggetto AltraClasse avrà questa caratteristica, avrà cioè la definizione di quel comportamento.
Da cui la domanda numero 2: posto che alla 1 tu abbia detto sì, tra le caratteristiche di questa pluralità di oggetti che si comporta come descritto in AltraClasse c'è la definizione di un comportamento? Oltre ad avere N nasi ed M bocche, gli oggetti di tipo AltraClasse devono anche definire qualcosa?
E per ultima la numero 3: TestMe è la definizione di un oggetto di tipo AltraClasse? - parlo di oggetto anche se TestMe è una classe C++ perchè in C++ un modulo non è polimorfico e quindi occorre usare le classi anche per definire gli oggetti.
Questo è OOP. Iniziare il discorso dalle classi tout-court è fare orientamento alle classi, prospettiva che al momento è nota solo a certi autori dalla mente confusa.
Una classe astratta ha senso quando hai bisogno di una classe più generica che non istanzierai mai in cui metti la base, ma poi definisci più classe figlie specializzate dove metti tutto.
Chiarissimo. Quindi nell'esempio citato, avendo varie classi specifiche e una che permette di gestire il tutto senza dover richiamare (per semplice comodità), mi conviene dichiarare le classi specifiche come classi astratte e poi derivarne la classe che gestisce il tutto o lasciare tutto com'è - ovvero le classi vengono inizializzate con riferimenti tra gli oggetti privati della classe - ?
Sò che è una cosa molta relativa, ma mi piacerebbe avere un parere, magari motivato, del perchè fare una scelta o un'altra.
Il tuo caso specifico (classe generica da cui si derivano quelle specifiche) mi è chiaro, ma questo non è il mio caso dato che ogni classe assolve un compito preciso che viene gestito da un metodo della classe "principale".
Es. la classe CancellaStringa contiene i suoi metodi per riconoscere e cancellare la stringa, e con la classe TestMe istanzio il metodo Cancella in cui esegue automaticamente tutti i passaggi necessari.
Grazie, ciao.
Stai cercando di riprendere in mano l'OOP eppure nel tuo intero post non c'è una sola volta la parola "oggetto". C'è qualcosa che non va. :p L'OOP l'ho utilizzato con PHP 5 (e se lo conosci capisci di che OOP parliamo). L'ho però studiato su un buon manuale di PHP interamente dedicato all'OOP (un bel mattone) e quindi ne parlava molto anche generalmente, introducendolo, prima di passare all'OOP versione PHP5.
Appena iniziai comunque lasciai PHP (e si parla di un buon annetto fà) quindi ho appreso le basi, sviluppato qualcosa e dato interessa all'OOP secondo le necessità.
Mi spiace se non ho ancora la terminologia adatta, cercherò di rimediare.
Inoltre in OOP tutto è un oggetto no? parlare di oggetto è generico (se ho ragione), quindi metodi e proprietà sono d'obbligo per farsi capire :p (sempre se ho ragione).
Non c'è alcuna convenienza nell'uso di una classe astratta rispetto ad un modulo piuttostoche ad una funzione.
Tutto quello che c'è sono gli oggetti che compongono il tuo sistema: è dalle caratteristiche di questi oggetti che ricavi la necessità di usare una classe totalmente o parzialmente definita o di non usarla affatto.
Quando usi una classe? Be', quando nel sistema hai una pluralità di oggetti che si comportano tutti quanti nello stesso modo.
Chiarissimo.
Dunque domanda numero 1: nel tuo sistema hai una pluralità di oggetti che si comportano tutti quanti nel modo definito in AltraClasse? Se sì, AltraClasse è una classe, altrimenti, in C++, è un modulo.
L'esempio è inventato sul momento, ma si, nel mio caso AltraClasse accetta solo oggetti che si comportano in quel modo, altrimenti usa una altra classe. Esempio la classe di gestione delle Eccezioni, l'ho realizzata sia perchè tutte le eccezioni vanno gestite in quel modo sia per poter mantenere meglio il codice e in vista di cambiamenti mi basta modificare quella classe o i suoi metodi e sono apposto.
Lo stesso vale per TestMe: pluralità -> classe, altrimenti modulo.
TestMe viene utilizzata per usufruire delle funzionalità delle altre classi. Anzichè dichiarare nel codice stesso un:
Exception* eccezioni = new Exception();
o nel caso AltraClasse* test = new AltraClasse();
Uso la classe TestMe che inizializza tutte le classi necessarie e quindi al verificarsi di date condizioni utilizzo i metodi previsti nella classe TestMe anzichè la classe specifica direttamente. E' un test che stò facendo supponendo di avere numerossime classi e che siano tutte utili al programma. Sono test che faccio per iniziare poi a scrivere un semplice engine 2D, in modo da poter utilizzare la classe Engine e gestire finestre e tutto da lì (anche se ogni cosa ha la sua classe specifica che ne definisce i metodi e le proprietà). Quindi a questa tua domanda, se TestMe è una classe o un modulo, sinceramente non saprei rispondere.
E veniamo all'astrazione. TestMe dev'essere una classe astratta? Be', bisogna capire cosa diamine sia quest'astrazione, no?
Abbiamo detto che una classe è la rappresentazione di una pluralità di oggetti i quali si comportano allo stesso modo. Ho diecimila oggetti che hanno un nome e un cognome - o due, pluralità è più di uno. La manifestazione di quel nome e cognome è il comportamento che tutti gli oggetti di tipo X condivide.
Per le classi astratte il principio è identico: più d'un oggetto ha uno stesso "set" di comportamenti. Tra questi comportamenti che tutti quanti gli oggetti di tipo X possiedono almeno uno consiste nella definizione di un comportamento. Ho un nome, ho un cognome e devo dire come faccio a camminare.
Che significa dire AltraClasse è una classe il cui metod abc è astratto? Esattamente come succederebbe per una classe "normale" significa dire che c'è più di un oggetto che si comporta come descritto in AltraClasse. Siccome AltraClasse dice che tra le sue caratteristiche c'è la definizione di un comportamento, ogni oggetto AltraClasse avrà questa caratteristica, avrà cioè la definizione di quel comportamento.
Quindi astratto o meno lo scopo del metodo è sempre lo stesso, mi pare di capire: dire che l'oggetto X possiede il metodo Y.
Da cui la domanda numero 2: posto che alla 1 tu abbia detto sì, tra le caratteristiche di questa pluralità di oggetti che si comporta come descritto in AltraClasse c'è la definizione di un comportamento? Oltre ad avere N nasi ed M bocche, gli oggetti di tipo AltraClasse devono anche definire qualcosa? Può essere considerato comportamento anche il semplice settaggio delle variabili dell'oggetto ? E la sua lettura? Insomma, i metodi (volgarmente mi verrebbe da dire le funzioni definite nella classe) sono le definizioni del comportamento, no?
E per ultima la numero 3: TestMe è la definizione di un oggetto di tipo AltraClasse? - parlo di oggetto anche se TestMe è una classe C++ perchè in C++ un modulo non è polimorfico e quindi occorre usare le classi anche per definire gli oggetti.
TestMe permette di definire un oggetto che tra i propri metodi ha quelli per gestire proprietà e oggetti attraverso i metodi di AltraClasse. In questo modo non ha senso, ma realmente si occupa di fornire tutti i metodi necessari al funzionamento del programma. In poche parole anzichè definire io nel codice una marea di oggetti, la classe TestMe li definisce tra i propri oggetti privati, mettendo a disposizione poi dei metodi per gestirli (il vantaggio è la comodità di dichiarare in seguito un solo oggetto e poter gestire tutto il funzionamento con i metodi a disposizione - che a loro volta gestiscono oggetti privati della classe -). Detta così è complicata, sicuramente per via della mia carenza in tecnicismi, ma spero di aver resto l'idea. Nel caso ti prego di dirmelo e provvederò quando prima a porvi rimedio in qualche modo.
Questo è OOP. Iniziare il discorso dalle classi tout-court è fare orientamento alle classi, prospettiva che al momento è nota solo a certi autori dalla mente confusa.
:)
Ti ringrazio mille, alla solita sei molto completo ed esaustivo nella risposta.
Purtroppo ho molte carenze e quel poco che sò (sapevo) si è arrugginito.
:(
Grazie mille della pazienza e del tempo dedicato,
buona notte.
Chiarissimo. Quindi nell'esempio citato, avendo varie classi specifiche e una che permette di gestire il tutto senza dover richiamare (per semplice comodità), mi conviene dichiarare le classi specifiche come classi astratte e poi derivarne la classe che gestisce il tutto o lasciare tutto com'è - ovvero le classi vengono inizializzate con riferimenti tra gli oggetti privati della classe - ?
Sò che è una cosa molta relativa, ma mi piacerebbe avere un parere, magari motivato, del perchè fare una scelta o un'altra.
Il tuo caso specifico (classe generica da cui si derivano quelle specifiche) mi è chiaro, ma questo non è il mio caso dato che ogni classe assolve un compito preciso che viene gestito da un metodo della classe "principale".
Es. la classe CancellaStringa contiene i suoi metodi per riconoscere e cancellare la stringa, e con la classe TestMe istanzio il metodo Cancella in cui esegue automaticamente tutti i passaggi necessari.
Grazie, ciao.
Data l'ora tarda potrei dire una fesseria, ma mi sembra di capire che vuoi fare questo http://en.wikipedia.org/wiki/Fa%C3%A7ade_pattern . Sbaglio?
Mi spiace se non ho ancora la terminologia adatta, cercherò di rimediare.
Non c'è nulla di cui dispiacersi, tutto si impara. Il supporto che PHP offre all'orientamento agli oggetti è completo. Bisogna poi vedere com'è trattato nei libri che ne parlano. Io avevo un libro su PHP5 (PHP5 e MySQL o una cosa del genere) che faceva schifo dal punto di vista dell'OOP.
Il primo punto fondamentale, essenziale, imprescindibile è: no, in un sistema osservato da un punto di vista orientato agli oggetti ci sono un sacco di cose che NON sono oggetti.
Cos'è un oggetto nella prospettiva orientata agli oggetti? Un oggetto nella prospettiva orientata agli oggetti è una definizione autonoma.
La definizione è una collezione denominata di predicati.
Predicare è dire qualcosa di: è blu, salta, si trova in (10,5), può contenere un punto, ha un'immagine eccetera.
E' denominata nel senso che al gruppo di predicati si attribuisce un nome.
E' autonoma nel senso che non è parte di altre definizioni.
E' necessario che sia autonoma perchè una definizione che non possieda almeno un carattere unico non è in grado di identificare una parte del sistema. E' come avere due matite sul tavolo: possono essere della stessa forma, colore, materiale, possono essere in tutto e per tutto uguali ma non possono essere identiche perchè se lo fossero non le percepiremmo più come distinte, come "due matite": ne percepiremmo una sola.
Tutta la partita dell'orientamento agli oggetti si gioca sul campo dell'autonomia.
La matita è un corpo tubolare di colore giallo. Quante definizioni ho? Tre, corpo, matita, colore. Quanti oggetti ho? Uno, la matita.
Quando vado a esaminare il sistema e mi trovo con colore, corpo e matita, scopro che tra queste tre definizioni ci sono delle relazioni. E in questo sistema, fatto di questre tre definizioni, chi è autonomo, nel senso di non essere parte di altre definizioni?
Colore: è parte della definizione di matita.
Corpo: è parte della definizione di matita.
Matita: non è parte di altre definizioni ergo.
Matita è una definizione autonoma ergo è un oggetto, Colore e Corpo sono definizioni ma non sono autonome quindi non sono oggetti.
Il secondo punto fondamentale è: la dipendenza di definizione è transitiva. Se Matita dipende da Colore e Colore dipende da Int allora Matita dipende da Int.
Tutti gli strumenti dei linguaggi orientati agli oggetti - classi, interfacce, classi astratte, moduli, collegamento dinamico, ereditarietà, composizione e via dicendo - e tutti i c.d. pattern, sono funzioni che ti permettono di controllare chi dipende da cosa e, in particolare, permettono di interrompere la catena di dipendenze che deriva dalla transitività della dipendenza.
Prendiamo il caso di TestMe. Diciamo che nel tuo sistema lo consideri un oggetto, lo consideri una parte autonoma del fenomeno che stai rappresentando. Supponiamo, per non farla troppo "strana", che in C++ una classe possa essere considerata la definizione di un oggetto - e non di una pluralità di oggetti tutti con lo stesso comportamento. E' vero, nel codice che segue, che TestMe è un oggetto?
#include <cstdlib>
#include <iostream>
using namespace std;
class TestMe {
public:
void funzioneUno() const {
cout << "funzione uno" << endl;
}
void funzioneDue() const {
cout << "funzione due" << endl;
}
};
class UtenteTestMe {
private:
TestMe utils;
public:
UtenteTestMe(TestMe u) {
utils = u;
}
void funzioneUtente() const {
utils.funzioneUno();
}
};
Numero di definizioni: due. TestMe e UtenteTestMe. Numero di oggetti?
TestMe è parte di UtenteTestMe
UtentTestMe usa TestMe e non è parte di nessuno.
Due definizioni, un oggetto... UtenteTestMe!
E TestMe che fine ha fatto? TestMe c'è, è una definizione, ma non è autonoma, quindi non è un oggetto.
Ci sono tante conseguenze per il fatto che una definizione non sia la definizione di un oggetto. Una importante è questa: una definizione che non sia la definizione di un oggetto è immutabile.
Deve essere considerata immutabile perchè se è parte di un'altra definizione - e prima o poi parte di uno o più oggetti - qualsiasi intervento su quella parte incide, possibilmente in modi disastrosi, su altre definizioni.
Ho il mio bell'oggetto matita, lì sul tavolo che mi guarda sorridendo, cambio la definizione di "corpo" e PAF, la matita mi diventa un'accendino, il resto del programma non lo sa, cerca di usarla per scrivere e, morale della favola, mi ritrovo con la scrivania in fiamme!
Come faccio a preservare l'autonomia di TestMe?
Attraverso l'astrazione.
#include <cstdlib>
#include <iostream>
using namespace std;
class TestMeType {
public:
virtual void funzioneUno() const = 0;
virtual void funzioneDue() const = 0;
};
class TestMe : public TestMeType {
public:
virtual void funzioneUno() const {
cout << "funzione uno" << endl;
}
virtual void funzioneDue() const {
cout << "funzione due" << endl;
}
};
class UtenteTestMe {
private:
TestMeType* utils;
public:
UtenteTestMe(TestMeType* u) {
utils = u;
}
void funzioneUtente() const {
utils->funzioneUno();
}
};
Numero di definizioni: tre. TestMeType, TestMe, UtenteTestMe.
TestMeType è usata da TestMe e UtenteTestMe.
TestMe usa TestMeType e non è usata da nessuno.
UtenteTestMe usa TestMeType e non usata da nessuno.
Numero di definizioni che sono anche definizioni di oggetto? Due: TestMe e UtenteTestMe.
Bingo.
L'astrazione di TestMeType permette a UtenteTestMe di "usare" TestMe senza dipendere da TestMe. E questa indipendenza permette a UtenteTestMe e TestMe di essere oggetti. Una delle conseguenze del fatto che UtenteTestMe e TestMe sono oggetti sta in ciò che tu a UtenteTestMe e TestMe puoi fare quel che preferisci senza che ciò pregiudichi la reciproca integrità.
Questo è lo scopo e l'applicazione della classi astratte.
Data l'ora tarda potrei dire una fesseria, ma mi sembra di capire che vuoi fare questo http://en.wikipedia.org/wiki/Fa%C3%A7ade_pattern . Sbaglio?
Mitico! Questo è quello che vorrei realizzare con la classe "principale" (facade!?!). Ovvero che attraverso l'oggetto istanziato con quella classe (o modulo, a sto punto PGI-Bis mi ha fatto sorgere un dubbio, dato che un solo oggetto verrà istanziato con quella classe... ovvero quello che poi mi permette di accedere ai vari metodi) posso utilizzare dei metodi che forniscono una astrazione su operazioni più complesse realizzate tramite i metodi di altri oggetti privati. Anche se spesso i metodi sono 1=1 ovvero semplicemente creo un metodo che corrisponde alla chiamata del metodo di un oggetto privato, per semplice comodità e facilità di utilizzo.
Da quel che vedo in wiki istanzia i vari oggetti, non estende la classe con le altre, quindi al mio quesito "se mi conviene, in questo caso creare classi astratte per derivarne la classe TestMe" suppongo che mi convenga lasciare ogni classe "normale" e istanziare gli opportuni oggetti private in TestMe !?!
Wow! Ti ringrazio per la chiarezza, tutto liscio come l'olio :)
Non c'è nulla di cui dispiacersi, tutto si impara. Il supporto che PHP offre all'orientamento agli oggetti è completo. Bisogna poi vedere com'è trattato nei libri che ne parlano. Io avevo un libro su PHP5 (PHP5 e MySQL o una cosa del genere) che faceva schifo dal punto di vista dell'OOP. Uhm. Il mio si intitolava (a caratteri cubitali gialli) PHP5, un bel blocco di 600 pagine se non ricordo male, che parlava anche dell'interazione con MySQL e addirittura della classe mysqli.
Il primo punto fondamentale, essenziale, imprescindibile è: no, in un sistema osservato da un punto di vista orientato agli oggetti ci sono un sacco di cose che NON sono oggetti.
Cos'è un oggetto nella prospettiva orientata agli oggetti? Un oggetto nella prospettiva orientata agli oggetti è una definizione autonoma. Oh, questa premessa ci stava a pennello, mi hai risolto molti dubbi.
Tutta la partita dell'orientamento agli oggetti si gioca sul campo dell'autonomia.
Chiarissimo.
La matita è un corpo tubolare di colore giallo. Quante definizioni ho? Tre, corpo, matita, colore. Quanti oggetti ho? Uno, la matita.
Quando vado a esaminare il sistema e mi trovo con colore, corpo e matita, scopro che tra queste tre definizioni ci sono delle relazioni. E in questo sistema, fatto di questre tre definizioni, chi è autonomo, nel senso di non essere parte di altre definizioni?
Colore: è parte della definizione di matita.
Corpo: è parte della definizione di matita.
Matita: non è parte di altre definizioni ergo.
Matita è una definizione autonoma ergo è un oggetto, Colore e Corpo sono definizioni ma non sono autonome quindi non sono oggetti.
Ti ringrazio per l'esempio, in questo modo hai evitato successive domande in merito all'autonomia. :)
Il secondo punto fondamentale è: la dipendenza di definizione è transitiva. Se Matita dipende da Colore e Colore dipende da Int allora Matita dipende da Int.
Giustissimo.
Tutti gli strumenti dei linguaggi orientati agli oggetti - classi, interfacce, classi astratte, moduli, collegamento dinamico, ereditarietà, composizione e via dicendo - e tutti i c.d. pattern, sono funzioni che ti permettono di controllare chi dipende da cosa e, in particolare, permettono di interrompere la catena di dipendenze che deriva dalla transitività della dipendenza.
Questa parte non mi è molto chiara. Quello che hai detto si, ma dovrò vedermi in che modo interrompono la catena delle dipendenze.
TestMe c'è, è una definizione, ma non è autonoma, quindi non è un oggetto.
Questo l'ho capito grazie all'esempio della matita in seguito :D
Come faccio a preservare l'autonomia di TestMe?
Attraverso l'astrazione. Oh! finalmente inizia ad essermi chiaro il motivo dell'astrazione.
// ...
class TestMeType {
public:
virtual void funzioneUno() const = 0;
virtual void funzioneDue() const = 0;
};
Qui ho bisogno di chiederti due cose, dato che sul web i casi sono rari e non spiegano il perchè:
- perchè dopo la dichiarazione delle funzioni virtuali usi la keyword const ? non ne capisco il significato...
- il significato di " = 0" ? Ho fatto qualche ricerca ma idem, non se ne parla. Ho però visto un esempio di una funzione dichiarata senza la keyword const che usa "= 0" ma alla solita si sofferma sull'esempio in generale.
L'astrazione di TestMeType permette a UtenteTestMe di "usare" TestMe senza dipendere da TestMe. E questa indipendenza permette a UtenteTestMe e TestMe di essere oggetti. Una delle conseguenze del fatto che UtenteTestMe e TestMe sono oggetti sta in ciò che tu a UtenteTestMe e TestMe puoi fare quel che preferisci senza che ciò pregiudichi la reciproca integrità.
Questo è lo scopo e l'applicazione della classi astratte.
Tutto chiarissimo. Se però dovessi cambiare la definizione della funzione in TestMe mi aspetto comunque un cambiamento anche in UtenteTestMe.
Ho comunque capito quello che intendi, in questo modo modificare TestMe non compromette UtenteTestMe.
Se invece dichiarassi due classi che ereditano dalla classe astratta e definiscono entrambi una versione differente dei metodi astratti secondo quale logica dovrei aspettarmi l'utilizzo di questo o quello?
Ho letto su una guida che la scelta della funzione avviene dinamicamente da parte del compilatore, in modo che corrisponda al tipo dell'oggetto, ma qui l'oggetto è dichiarato come puntatore alla classe astratta.
Proverò qualche esempio incrociato in modo da definire anche con la pratica come si comporta in questa condizione, ma se sai come si comporta mi faresti un (ulteriore) favore :)
Ti ringrazio per il tempo dedicatomi per la spiegazione di questo concetto.
Sei stato davvero molto gentile ed esaustivo.
Facendo pochissimo sforzo, potresti raccogliere il contenuto di questi post e farne una guida per il forum :D L'hai praticamente già fatta, e inoltre è molto dettagliata -cosa rara in rete, quando si parla di OOP-.
Grazie ancora e buona giornata!
[EDIT]
Ho letto un tutorial in rete sulle funzioni virtuali, e ho risolto il quesito del "multiplo overloading" di una funzione virtuale. Quello che mi sfuggiva era:
public:
UtenteTestMe(TestMeType* u) {
utils = u;
}
Qui passi il tipo di classe che voglio utilizzare assegnando il valore a utils.
Nel caso quindi passerò TestMe per usare la sua funzione, se ho ben capito.
Quindi ora anche questo mi torna chiaro :)
In questo modo posso anche evitare di accedere ad altre funzioni di TestMe se non sbaglio! (non essendo le altre dichiarate nella classe astratta).
const dopo la lista di argomenti indica che la funzione non può modificare i dati membro dell'oggetto.
class Base {
private:
int valore;
public:
void funzione() const {
valore = 10; //non compila, funzione() è const, non può modificare il membro "valore"
}
};
Se non metti "const" allora la funzione può modificare i dati membro.
class Base {
private:
int valore;
public:
void funzione() {
valore = 10; //ok
}
};
Ci sono tante ragioni per dichiarare const una funzione. Una è che se la funzione dichiara di non modificare dati membro allora essa sarà in grado di operare su istanza dichiarate const. Se ho un'istanza b costante:
const Base* b = qualcosa;
su b non posso invocare funzioni membro non costanti.
= 0 indica che la funzione virtuale è "pura" cioè la classe base non da una definizione di quella funzione ma saranno le singole sottoclassi non astratte a dover necessariamente definire quella funzione. Nota che "= 0" è una cosa e "const" è un'altra: l'uno non richiede l'altro.
const dopo la lista di argomenti indica che la funzione non può modificare i dati membro dell'oggetto. per l'esattezza i qualificatori messi dopo la lista di argomenti sono qualificatori tramite i quali viene definita la versione di this passata al metodo, quindi se ci metti const non ti arriva un puntatore ad un oggetto ma un puntatore ad un oggetto const.
anzi, siccome this é un puntatore const la frase é meglio formulata come: non ti arriva un puntatore const ad un oggetto ma un puntatore const ad un oggetto const.
dopodiché i campi non sono modificabili perché i campi di un oggetto o struttura const sono anch'essi const.
banryu79
09-09-2009, 13:11
Ehm, illuminante il post di PGI sull'OOP...
Tra le varie spiegzioni/descrizioni di questa prospettiva che ho letto non avevo mai trovato delle definizioni così precise circa l'oggetto e le sue relazioni: devo dire che vista così mi sembra una cosa meno campata in aria e più precisa, circostanziata.
Ma dove si trovano queste informazioni? Cioè, c'è qualche testo serio che definisca in questo modo la prospettiva OOP? Magari agnostico rispetto al linguaggio di programmazione?
Insomma, qualcosa che spieghi come ha fatto PGI qui, le conseguenze delle varie relazioni di dipendenza tra le definizioni di un sistema OOP e le conseguenze per gli oggetti che si vanno così' definendo... sarebbe estremamente utile e interessante :)
Grazie mille a tutti :oink:
Per le spiegazioni, in particolar modo a PGI-Bis per l'esaustiva spiegazione di quanto chiesto "e oltre"! :)
Visto che godiamo di un così abile elemento nell'OOP se avrò altri dubbi che non riesco a risolvere posterò nuovamente sul forum :p
Ikon O'Cluster
09-09-2009, 22:38
Non ho letto gli altri post, ma se vuoi un procedimento logico per capire quando usare una classe astratta e più in generale la derivazione e quando utilizzare il polimorfismo considera questi due esempi:
class Persona {
char* Nome;
unsigned int anni;
// ...
}
class Lavoratore : public Persona {
// ...
}
class Studente : public Persona {
// ...
}
In questo caso tra le Persone e i Lavoratori e Studenti vi è una relazione di tipo "è un". Ad esempio "Persona è un Lavoratore", ma vale anche che "Lavoratore è una Persona". In questi casi la relazione essendo di tipo "è un" va tradotta con una derivazione ed in particolare se ad esempio tutte le persone considerate possono essere o Lavoratori oppure Studenti allora Persona potrà tranquillamente essere una classe astratta. In generale una classe astratta definisce una "interfaccia" cioè una serie di funzioni e di variabili che devono essere presenti in tutte le classi che derivano da essa. Ad esempio:
class Contenitore {
Oggetto* lista;
public:
virtual Oggetto leva() = 0;
virtual void metti(Oggetto* o) = 0;
}
class Portagioielli : public Contenitore;
class Gioiello : public Oggetto;
In tal caso un contenitore di per sé è un concetto astratto quindi non istanziabile, però se si parla di gioielli un contenitore di gioielli è un portagioielli. Le funzioni "leva" e "metti" dipendono dal particolare tipo di contenitore. Per esempio la classe:
class Scatolone : public Contenitore;
Avrà una funzione "metti" del tipo:
void metti(Oggetto* o) {
if(!pieno) {
accoda(o, lista);
return;
}
if(!chiuso) imballa_con_scotch();
}
Quindi come vedi il Portagioielli non potrebbe essere imballato con scotch... quindi bisogna specializzare, però in sostanza il concetto di "mettere" oggetti all'interno è sempre lo stesso.
class Persona {
//...
Animale* animale_domestico;
}
class Animale {
//...
Persona* padrone;
public:
virtual char* emetti_verso() = 0;
}
class Gatto : public Animale {
public:
virtual char* emetti_verso() {return "miao"};
}
class Cane : public Animale {
public:
virtual char* emetti_verso() {return "bau"};
}
Puoi anche notare come ho fatto un esempio ulteriore di derivazione dove "Animale è un Cane" e "Animale è un Gatto" e si nota come non esistano in natura "istanze" di Animale (del quale non si conoscerebbe il verso). Esistono solo istanze di Gatti, Cani, ecc... Tuttavia tutte le sotto-classi hanno caratteristiche comuni: ad esempio emettono un verso, hanno un padrone, ecc.... Quindi hanno la stessa "interfaccia".
Inoltre c'è nel mezzo anche una nuova relazione: "Persona ha un Animale" mentre "Animale ha una Persona" (cioè ha un padrone...). Questa relazione "ha un" puoi rappresentarla con il polimorfismo. QUesto ti permette di fare in modo che il proprietario di cane sia un Lavoratore o uno Studente. Mentre a un Lavoratore o a uno Studente puoi associare un Cane o un Gatto o un Coccodrillo! O_O
Esempi banalissimi, ma quando ti trovi a progettare il codice devi necessariamente assorbito queste primitive di OOP in modo da applicare la giusta soluzione in ogni occasione. Spesso quando ti accorgi che le cose non tornano perchè si cominciano ad ingarbugliare è proprio perchè una gerarchia di classi è sbagliata o altre questioni di progettazione. Alla fine scrivere il codice (sviluppo) è una cosa, invece progettarlo ne è un'altra. Bisognerebbe spiegarlo a quelli che mandano gli Informatici a fare lo stesso esame di stato che fanno gli Ingegneri Informatici... così alla fine diventa Ingegnere anche uno che la progettazione non ce l'ha nella testa, malgrado capisca l'UML!
mindwings
11-09-2009, 08:20
Il termine astrazione e' usato in maniera impropria... Dovremmo parlare di *INDIREZIONE* che appunto viene usata per rompere la dipendenza dall'implementazione concreta. La dipendenza non sparisce magicamente ma viene sostituita la dipendenza concreta con una non concreta. Qui c'e' un bell'articolo a riguardo -> http://www.zedshaw.com/essays/indirection_is_not_abstraction.html
Non credo che l'autore parli di questioni relative all'orientamento agli oggetti. Altrimenti non direbbe:
"Even more proof comes from the fact that Java uses the keyword “abstract” to create objects which actually support indirection."
Spiegare concetti di OOP attraverso un linguaggio OOP significa usare una conseguenza per giustificare una causa.
La causa di un incidente in macchina non è il fatto di aver abbattuto un albero: sarà stata la distrazione, la perdita di controllo, qualsiasi cosa che è venuta prima della conseguenza.
E non va meglio con la definizione precedente:
“(v) The process of separating the interface to some functionality from the underlying implementation in such a way that the implementation can be changed without changing the way that piece of code is used. (n) The API (interface) for some piece of functionality that has been separated in this way.”
Anche qui, il codice è una conseguenza. Programmazione orientata agli oggetti è la traduzione della rappresentazione di un fenomeno interpretato alla luce dei principi dell'orientamento agli oggetti.
Esattamente come programmazione procedurale è la traduzione della rappresentazione di un fenomeno interpretato alla luce dei principi di funzionamento di un calcolatore.
Fa un discorso su Java e peraltro su un aspetto molto specifico del linguaggio. Col quale, a onor del vero, non sembra avere grande dimestichezza.
mindwings
11-09-2009, 11:03
Non credo che l'autore parli di questioni relative all'orientamento agli oggetti. Altrimenti non direbbe:
"Even more proof comes from the fact that Java uses the keyword “abstract” to create objects which actually support indirection."
Spiegare concetti di OOP attraverso un linguaggio OOP significa usare una conseguenza per giustificare una causa.
La causa di un incidente in macchina non è il fatto di aver abbattuto un albero: sarà stata la distrazione, la perdita di controllo, qualsiasi cosa che è venuta prima della conseguenza.
L'articola discute circa il significato di astrazione e indirezione... Nessuno ha detto che discute l'oop nella sua interezza nemmeno l'autore.
Ecco l'argomento in esame dell'articolo:
The point I’ll be trying to make throughout the essay is simple: Abstraction and indirection are very different yet cooperating concepts with two completely different purposes in software development. Abstraction is used to reduce complexity. Indirection is used to reduce coupling or dependence. The problem is that programmers frequently mix these up, using one for the other purpose and just generally screwing things up.
E non va meglio con la definizione precedente:
There’s one “definition” of abstraction that lays out the entire basis for my argument very clearly:
“(v) The process of separating the interface to some functionality from the underlying implementation in such a way that the implementation can be changed without changing the way that piece of code is used. (n) The API (interface) for some piece of functionality that has been separated in this way.”
Notice that this definition is entirely different from the others. It doesn’t mention words like “abridged, summarize, concentrate, concrete, general, or common”?
E' chiaro che se quoti alcuni pezzi omettendone altri non si capisce cosa vuole dire l'autore... Ho aggiunto i pezzetti da te omessi in bold.
Altro "E non va meglio con la definizione precedente", critichi l'autore su una definizione che non piace nemmeno all'autore... :asd:
Fa un discorso su Java e peraltro su un aspetto molto specifico del linguaggio. Col quale, a onor del vero, non sembra avere grande dimestichezza.
Da cosa lo deduci? Sfera di cristallo?!
Invito chiunque sia interessato a leggere l'articolo e di non accontentarsi
dei riassuntini di nessuno. Le informazioni vanno contestualizzate e analizzate
Io ho a volte ho la seria impressione di parlare una lingua sconosciuta.
Io parlo di orientamento agli oggetti. E il mio punto relativo a quel blog è quello che ho messo come prima frase nella mia risposta:
Non credo che l'autore parli di questioni relative all'orientamento agli oggetti.
Naturalmente con ciò presuppongo che qui noi stiamo affrontando un problema di orientamento agli oggetti. E per questo dico: attenzione che quel blog parla di un'altra cosa.
E porto due indizi a giustificazione di questa mia affermazione. Il fatto che l'autore tiri in ballo un aspetto molto specifico di un particolare linguaggio di programmazione e il fatto che discuta una definizione che è altrettanto particolare.
Ho forse scritto che l'autore aderisce ad una definizione e dimostrato che quella definizione è sbagliata? Non mi sembra.
Sono più che d'accordo sul fatto che quando uno cita un pezzo di un testo c'è sempre il rischio che si perda o addirittura si stravolga il significato di quella parte di testo. A me però non interessava la conclusione dell'autore sulla definizione che cita ma il fatto che argomentando intorno a quella definizione risultasse chiara l'estraneità della discussione al tema dell'orientamento agli oggetti.
Sul fatto che parlando di Java dimostri una scarsa conoscenza del linguaggio, lo confermo. Non è la sfera di cristallo a dirmelo ma la conoscenza teorica e pratica del linguaggio, unita alle stupefacenti imposizioni che l'autore attribuisce alla parola chiave abstract.
Even more proof comes from the fact that Java uses the keyword “abstract” to create objects which actually support indirection. Think about it, the “abstract” keyword doesn’t reduce, summarize, or generalize a more concrete implementation, but rather creates an indirect path to the real implementation of that function. If this “abstract” class were to follow the previous definitions it would simply reduce the number of functions needed to use the actual concrete implementation. But, when you implement an “abstract” Java class you must implement the same number of functions including the abstract functions just to get it work.
Le due frasi in grassetto sono sbagliate: non dico imprecise, dico proprio sbagliate. Presuppongono regole di un linguaggio diverso da Java.
banryu79
11-09-2009, 13:01
Sono d'accordo con PGI per quanto riguarda il fatto che l'autore di quell'articolo non parla di questioni rientranti nella prospettiva di programmazione orientata agli oggetti.
Le due frasi in grassetto sono sbagliate: non dico imprecise, dico proprio sbagliate. Presuppongono regole di un linguaggio diverso da Java.
Sì, ma bisogna, secondo me, interpretarle usando come filtro le premesse fatte dall'autore dell'articolo. Ovvero che tutto il suo discutere riguarda la precisa definizione della parola "abstract" nella lingua iglese, e di quello che invece comporta la stessa parola nel linguaggio Java.
Ammetto però che l'autore dell'articolo mi sembra peccare di ingenuità: secondo lui la keyword "abstract" in Java è misleading per il novello programmatore perchè il suo significato non è isomorfo a quello della parola "abstract" nel linguaggio naturale...
Essendo Java un linguaggio di programmazione, uno ne tiene conto e non può aspettarsi che ogni parola usata come keyword nel linguaggio formale abbia lo stesso significato della stessa parola usata nel linguaggio naturale...
Non ho letto gli altri post, ma se vuoi un procedimento logico per capire quando usare una classe astratta e più in generale la derivazione e quando utilizzare il polimorfismo considera questi due esempi:
Grazie mille per gli esempi :)
Molto utili.
@mindwings: Grazie per il link, lo leggerò.
Non mi unisco alla discussione in merito all'articolo primo perchè non l'ho letto, poi perchè non conosco java. Ma se volete discuterne fate pure, tutto può essere utile all'apprendimento :).
mindwings
11-09-2009, 18:35
@PGI Parliamo due lingue diverse, anche se l'autore non ha il rigore formale della Java Language Specification entrambi riusciamo a capire cosa intende e con questo chiudo.
mindwings
11-09-2009, 18:39
Grazie mille per gli esempi :)
Molto utili.
@mindwings: Grazie per il link, lo leggerò.
Non mi unisco alla discussione in merito all'articolo primo perchè non l'ho letto, poi perchè non conosco java. Ma se volete discuterne fate pure, tutto può essere utile all'apprendimento :).
Non c'e' di che se ho qualcosa di interessante in genere la condivido :D
per quanto ne sappia io,l' uso di classi astratte consiste nel definire la classe con i dati memmro e le interfacce delle funzioni membro senza l' implementazione)...l' implementazione dei metodi sarà fatta in una classe derivata(ereditarietà)...non è detto che sia la successiva a definire il metodo,ma potrebbe anche essere la classe derivata della classe derivata...
Giuseppe Sottile
12-09-2009, 16:21
Sono d'accordo con lupin87 ed aggiungo anche che da una classe astratta ovviamente non si possono istanziare oggetti e che in C++ una classe è astratta se contiene almeno una funzione virtuale pura. ;)
Sono d'accordo con lupin87 ed aggiungo anche che da una classe astratta ovviamente non si possono istanziare oggetti e che in C++ una classe è astratta se contiene almeno una funzione virtuale pura. ;)
:) Grazie mille, anche a Lupin87.
PS. dal numero di messaggi deduco tu sia nuovo del forum: benvenuto!
nuovoUtente86
16-09-2009, 11:25
Non c'è nulla di cui dispiacersi, tutto si impara. Il supporto che PHP offre all'orientamento agli oggetti è completo. Bisogna poi vedere com'è trattato nei libri che ne parlano. Io avevo un libro su PHP5 (PHP5 e MySQL o una cosa del genere) che faceva schifo dal punto di vista dell'OOP.
Il primo punto fondamentale, essenziale, imprescindibile è: no, in un sistema osservato da un punto di vista orientato agli oggetti ci sono un sacco di cose che NON sono oggetti.
Cos'è un oggetto nella prospettiva orientata agli oggetti? Un oggetto nella prospettiva orientata agli oggetti è una definizione autonoma.
La definizione è una collezione denominata di predicati.
Predicare è dire qualcosa di: è blu, salta, si trova in (10,5), può contenere un punto, ha un'immagine eccetera.
E' denominata nel senso che al gruppo di predicati si attribuisce un nome.
E' autonoma nel senso che non è parte di altre definizioni.
E' necessario che sia autonoma perchè una definizione che non possieda almeno un carattere unico non è in grado di identificare una parte del sistema. E' come avere due matite sul tavolo: possono essere della stessa forma, colore, materiale, possono essere in tutto e per tutto uguali ma non possono essere identiche perchè se lo fossero non le percepiremmo più come distinte, come "due matite": ne percepiremmo una sola.
Tutta la partita dell'orientamento agli oggetti si gioca sul campo dell'autonomia.
La matita è un corpo tubolare di colore giallo. Quante definizioni ho? Tre, corpo, matita, colore. Quanti oggetti ho? Uno, la matita.
Quando vado a esaminare il sistema e mi trovo con colore, corpo e matita, scopro che tra queste tre definizioni ci sono delle relazioni. E in questo sistema, fatto di questre tre definizioni, chi è autonomo, nel senso di non essere parte di altre definizioni?
Colore: è parte della definizione di matita.
Corpo: è parte della definizione di matita.
Matita: non è parte di altre definizioni ergo.
Matita è una definizione autonoma ergo è un oggetto, Colore e Corpo sono definizioni ma non sono autonome quindi non sono oggetti.
Il secondo punto fondamentale è: la dipendenza di definizione è transitiva. Se Matita dipende da Colore e Colore dipende da Int allora Matita dipende da Int.
Tutti gli strumenti dei linguaggi orientati agli oggetti - classi, interfacce, classi astratte, moduli, collegamento dinamico, ereditarietà, composizione e via dicendo - e tutti i c.d. pattern, sono funzioni che ti permettono di controllare chi dipende da cosa e, in particolare, permettono di interrompere la catena di dipendenze che deriva dalla transitività della dipendenza.
Prendiamo il caso di TestMe. Diciamo che nel tuo sistema lo consideri un oggetto, lo consideri una parte autonoma del fenomeno che stai rappresentando. Supponiamo, per non farla troppo "strana", che in C++ una classe possa essere considerata la definizione di un oggetto - e non di una pluralità di oggetti tutti con lo stesso comportamento. E' vero, nel codice che segue, che TestMe è un oggetto?
#include <cstdlib>
#include <iostream>
using namespace std;
class TestMe {
public:
void funzioneUno() const {
cout << "funzione uno" << endl;
}
void funzioneDue() const {
cout << "funzione due" << endl;
}
};
class UtenteTestMe {
private:
TestMe utils;
public:
UtenteTestMe(TestMe u) {
utils = u;
}
void funzioneUtente() const {
utils.funzioneUno();
}
};
Numero di definizioni: due. TestMe e UtenteTestMe. Numero di oggetti?
TestMe è parte di UtenteTestMe
UtentTestMe usa TestMe e non è parte di nessuno.
Due definizioni, un oggetto... UtenteTestMe!
E TestMe che fine ha fatto? TestMe c'è, è una definizione, ma non è autonoma, quindi non è un oggetto.
Ci sono tante conseguenze per il fatto che una definizione non sia la definizione di un oggetto. Una importante è questa: una definizione che non sia la definizione di un oggetto è immutabile.
Deve essere considerata immutabile perchè se è parte di un'altra definizione - e prima o poi parte di uno o più oggetti - qualsiasi intervento su quella parte incide, possibilmente in modi disastrosi, su altre definizioni.
Ho il mio bell'oggetto matita, lì sul tavolo che mi guarda sorridendo, cambio la definizione di "corpo" e PAF, la matita mi diventa un'accendino, il resto del programma non lo sa, cerca di usarla per scrivere e, morale della favola, mi ritrovo con la scrivania in fiamme!
Come faccio a preservare l'autonomia di TestMe?
Attraverso l'astrazione.
#include <cstdlib>
#include <iostream>
using namespace std;
class TestMeType {
public:
virtual void funzioneUno() const = 0;
virtual void funzioneDue() const = 0;
};
class TestMe : public TestMeType {
public:
virtual void funzioneUno() const {
cout << "funzione uno" << endl;
}
virtual void funzioneDue() const {
cout << "funzione due" << endl;
}
};
class UtenteTestMe {
private:
TestMeType* utils;
public:
UtenteTestMe(TestMeType* u) {
utils = u;
}
void funzioneUtente() const {
utils->funzioneUno();
}
};
Numero di definizioni: tre. TestMeType, TestMe, UtenteTestMe.
TestMeType è usata da TestMe e UtenteTestMe.
TestMe usa TestMeType e non è usata da nessuno.
UtenteTestMe usa TestMeType e non usata da nessuno.
Numero di definizioni che sono anche definizioni di oggetto? Due: TestMe e UtenteTestMe.
Bingo.
L'astrazione di TestMeType permette a UtenteTestMe di "usare" TestMe senza dipendere da TestMe. E questa indipendenza permette a UtenteTestMe e TestMe di essere oggetti. Una delle conseguenze del fatto che UtenteTestMe e TestMe sono oggetti sta in ciò che tu a UtenteTestMe e TestMe puoi fare quel che preferisci senza che ciò pregiudichi la reciproca integrità.
Questo è lo scopo e l'applicazione della classi astratte.
Discorso molto dettagliato che riporta al concetto di altà coesione e basso accoppiamento.
Resto perplesso su un punto però
TestMeType è usata da TestMe e UtenteTestMe.
TestMe usa TestMeType e non è usata da nessuno.
UtenteTestMe usa TestMeType e non usata da nessuno.
Numero di definizioni che sono anche definizioni di oggetto? Due: TestMe e UtenteTestMe.
Che nel blocco di codice ad esame è evidentemente vera, ma se analizzassimo un progetto più ampio ad un certo punto troveremmo sicuramente qualche definizione che utilizza o delaga UtenteTestMe, e cosi andando a ritroso si arriverebbe ad avere solo la classe o modulo di startup(main) pienamente autonoma e quindi eventualmente definibile oggetto se accettiamo la definizione data su. Anche perchè in un contesto OO un oggetto (o definizione)pienamente autonomo, ovvero a tenuta stagna, sarebbe un' entità inutile se non "stimolata" dall' esterno a svolgere qualcosa.
Discorso molto dettagliato che riporta al concetto di altà coesione e basso accoppiamento.
Resto perplesso su un punto però
Che nel blocco di codice ad esame è evidentemente vera, ma se analizzassimo un progetto più ampio ad un certo punto troveremmo sicuramente qualche definizione che utilizza o delaga UtenteTestMe, e cosi andando a ritroso si arriverebbe ad avere solo la classe o modulo di startup(main) pienamente autonoma e quindi eventualmente definibile oggetto se accettiamo la definizione data su. Anche perchè in un contesto OO un oggetto (o definizione)pienamente autonomo, ovvero a tenuta stagna, sarebbe un' entità inutile se non "stimolata" dall' esterno a svolgere qualcosa.
Se intendo correttamente, è il "problema del new".
La questione è pratica ed è anche molto delicata. E' il problema della creazione che non è un problema di prospettiva orientata agli oggetti ma di programmazione orientata agli oggetti - cioè di rappresentazione di ciò che è visto in termini orientati agli oggetti.
In un sistema orientato agli oggetti non c'è bisogno di creare gli oggetti: ci sono già, sono lì, esistono in quanto parte del sistema - che è una delle tre cose che in un sistema orientato agli oggetti non è oggetto e che pertanto non li assorbe.
In un programma oo invece gli oggetti bisogna crearli.
Due soluzioni.
La prima è creare gli oggetti - nel senso tecnico di istanziarli - in un unico punto del programma e "far finta" che quello sia il sistema, nel senso predetto.
Non è formalmente rigoroso perchè, come hai già notato, quello diventa il punto in cui tutte le definizioni di oggetto appaiono insieme e, quindi, perdono la loro autonomia.
Per me in Java o C++ è la soluzione preferibile perchè è molto semplice: metti i new nel main e via.
Sarebbe tuttavia preferibile usare meccanismi di caricamento dinamico. Ad esempio in Java è piuttosto comune che per sistemi c.d. modulari l'istanziazione non avvenga direttamente con un new Pippo() ma sfrutti i ClassLoader e dica Class.forName("pippo").
Il Class.forName("pippo") rispetta l'autonomia degli oggetti sia formalmente (c'è una stringa non c'è la classe pippo) sia praticamente (il forName è delegabile quindi io posso caricare una qualsiasi classe partendo da quella stringa).
Ma si può fare anche in C++ con una factory che crea istanze di un tipo specificato in una classe base astratta usando delle librerie dinamiche.
All'atto pratico, per un linguaggio che richiede una pre-compilazione, un sintomo del fatto che esso è propriamente diviso in oggetti si evince nel momento in cui rimuovendo quella parte del programma che corrisponde ad una definizione di oggetto il programma rilsuta comunque compilabile.
Una volta adottatta "'istanziazione dinamica" si risolve anche il problema dell'impossibilità da parte di un oggetto in senso proprio di offrire effettivamente un servizio agli altri oggetti.
nuovoUtente86
16-09-2009, 14:34
Si inquadrando la questione dal punto di vista di un software orienta agli oggetti una delle questioni basilari è l' istanziazione, ma dopo tale fase utilizzerò in qualche modo l' oggetto, ed evidentemente se ho utilizzato un forte accoppiamento in caso di modifiche mi ritroverò in un mare di guai...e questo purtroppo è un dato di fatto.
Dal lato prospettiva ad oggetti invece resto ancora dubbioso: se ho ben capito il tuo discorso, la definizione di oggetto porta alla soluzione black-box (che dovrebbe cmq essere intrinseca di una classe) però senza via di comunicazione con l' esterno, pena la perdità di autonomia e la classificazione ad oggetto. Se la definizione A è in rapporto di Has-a con B, B non è un oggetto. Ma se B fosse autonomo sarebbe anche inutilizzato, e quindi di nessuna utilità al contesto.
Una curiosità ma cosa indichi con c.d.
così detto/a
Un oggetto può essere autonomo e usato al tempo stesso. Basta che chi lo usa non faccia riferimento alla definizione dell'oggetto ma ad una parte di quella definizione - che sarà condivisa e quindi manipolabile solo a patto di sapere che si sta intervenendo su almeno due parti del programma.
L'interfaccia: tipico strumento di comunicazione che preserva l'identità.
interfaccia A
fai qualcosa
object B extends A
fai qualcosa ... e fai qualcosa per davvero, magari apre una base dati,
fa una telefonata o che so io.
interfaccia C
setA(a:A)
object D extends C
setA(a:A) ... usa a
A a = (A)carica("B")
C c = (C)carica("D")
if(a != null && c != null) {
C.setA(a);
}
Qui abbiamo D che usa B, attraverso A ma nè D nè B sono nominati.
non so se l'ho ricordato: la dipendenza di definizione è transitiva ma NON E' riflessiva: se X dipende da Y, Y non è detto che dipenda da X.
Mi premerebbe tuttavia sottolineare un punto. Non è che siccome quello pesudocodice è fatto com'è fatto allora è OO mentre non è OO una cosa che sia diversa da quella. Parliamo di prospettiva, di interpretazione del codice. Parliamo delle conseguenze che derivano dall'avere o non avere certe dipendenze. Non c'è un mitologico "buon orientamento agli oggetti" o un codice che sia "più orientato agli oggetti di un altro". C'è solo l'orientamento agli oggetti.
nuovoUtente86
16-09-2009, 16:15
così detto/a
non so se l'ho ricordato: la dipendenza di definizione è transitiva ma NON E' riflessiva: se X dipende da Y, Y non è detto che dipenda da X.
Spunto interessante per fare una riflessione sul rapporto autonomia e dipendenza. Un oggetto autonomo è tale se non crea dipendenza ad alcuno, ma non è immune dai cambiamenti altrui (di chi ingloba nella propria definizione). Credo questo sia un punto delicato che può indurre a volte in errore, intendendo l' autonomia come la non dipendenza da altre definizioni.
Facendo un sunto possiamo affermare?(punto interrogativo) che ogni definizione(che non possa essere immutabile) non autonoma, per diventare tale, debba essere astratta al suo "contratto" e legata, con opera di bridging,ad una sua implementazione reale (magari con approccio lazy).
Sui principi io resterei "generico", nel senso di limitare il discorso a definizioni che sono parti di altre e definizioni che non lo sono e che quindi sono definizioni di oggetti. E' questo il senso di quel "autonoma": che non è parte di.
Come si realizza in codice questa autonomia - in particolare quando ci si trova di fronte alla normale necessità di far parlare due oggetti - dipende dal linguaggio.
Ci sono strumenti comuni. Se uno va a guardare un modo diffuso per passare ad un oggetto un riferimento ad un altro oggetto senza che il primo riceva l'intera definizione del secondo nota la sequenza astrazione-ereditarietà-composizione-polimorfismo.
Non credo però che sia l'unico modo. Anche un programma che non facesse uso di astrazione o ereditarietà o composizione o polimorfismo potrebbe dirsi orientato agli oggetti se dall'esame del codice risultasse l'esistenza di almeno due oggetti.
Ad esempio un listato C, senza particolari escamotage, risulta composto di un unico oggetto che racchiude in sè tutte le funzioni del sistema, ma se iniziassimo ad appoggiarci al caricamento dinamico di librerie probabilmente saremmo in grado di ottenere quel tanto di separazione necessaria e sufficiente affinchè parti diverse del sistema siano definibili autonome.
Io penso che si debba stare attenti nel passaggio dalla prospettiva orientata agli oggetti alla programmazione orientata agli oggetti a non confondere le proprietà di un linguaggio con i principi della prospettiva.
banryu79
17-09-2009, 08:55
PGI, da qualche parte ho letto la tua affermazione circa il fatto che in un sistema orientato agli oggetti ci sono almeno 3 cose che non sono oggetti, e che il sistema stesso è una di queste, dico bene?
Quali sarebbero le altre 2, che non sono oggetti?
E perchè il sistema non dovrebbe essere un oggetto?
Nel senso: se prendo Java, da un certo punto di vista potrei considerare la definizione della così detta Main Class del mio applicativo come una definizione autonoma, quindi come un oggetto, che tra l'altro equivale al sistema.
O forse mi perdo da qualche parte?
In un sistema orientato agli oggetti le tre cose che non sono oggetti sono:
i predicati;
le definizioni non autonome;
il sistema;
i predicati sono definizioni di principio preesistenti e, qualora debbano essere condivisi, di natura convenzionale. Io assumo una certa definizione di "colore rosso" o di "colorato" o di "mobile" eccetera, dopodichè vado a guardare il sistema attribuendo quei predicati.
le definizioni non autonome sono quelle definizioni che non partecipano ad altre definizioni.
il sistema (di oggetti) è la rappresentazione che risulta dall'osservazione del fenomeno dal punto di vista orientato agli oggetti.
Se considerassimo il sistema come un oggetto allora sarebbe anche l'unico oggetto (il sistema è ciò di cui tutti gli oggetti sono parte, un oggetto che è parte di un oggetto non è esso stesso un oggetto, quindi gli oggetti decadono a definizioni non autonome).
Considerare il sistema come oggetto andrebbe anche bene, non fa un grinza rispetto ai principi, ma non è molto utile.
L'orientamento agli oggetti non è un modo per scrivere programmi con meno linee di codice o per scrivere programmi più velocemente o più veloci o chissà che. E' un modo per scrivere programmi complessi.
La divisione in oggetti permette di gestire quella complessità nel senso ultimo di conoscere le conseguenze di un intervento su una parte del programma PRIMA di intervernire. So che io posso modificare un oggetto e tu puoi modificarne un altro in parallelo ma non possiamo intervenire su due definizioni non autonome perchè corriamo il rischio di metterci vicendevolmente i bastoni tra le ruote. Cose così.
E' chiaro allora che nel momento in cui io vado ad interpretare il sistema stesso in termini OO e lo identifico di conseguenza come l'unico oggetto possibile tutta la "gestione" della complessità va a farsi benedire: qualsiasi modifica diventa possibile e irrilevante perchè comunque sto modificando tutto quanto, non è possibile dividere il lavoro perchè c'è un oggetto solo su cui intervenire eccetera eccetera.
banryu79
17-09-2009, 10:19
Ok.
Quindi è un fatto che la Main Class del mio programma Java, osservato dalla prospettiva orientata agli oggetti è un oggetto in quanto definizione autonoma, ma, diciamo così, non mi conviene considerarlo tale, altrimenti i benefici che potrei io essere umano avere, nell'utilizzare tale prospettiva, se ne vanno al diavolo.
C'è qualcosa che non mi torna... o forse non ho analizzato bene a fondo le cose.
Direi di no. Osserva il programma in termini di definizioni, autonome e non. Risulta uno schema: alcune parti del programma dipendono da altre, alcune non dipendono da nulla.
Se alla fine di questa lettura ti risulta che tutto dipende da tutto, cioè che non ci sono oggetti a parte il programma considerato nella sua interezza, il programma è ok, va bene, ma la sua complessità non è gestibile in termini di orientamento agli oggetti.
Si può sempre fingere che un particolare punto del programma sia il "sistema" - non è detto che sia il main - ma se non è una cosa voluta sin dall'inizio la divisione in oggetti che ne risulta non corrisponderà al fenomeno che il programma rappresenta.
banryu79
17-09-2009, 10:54
Direi di no.
Ok, mi sono appena reso conto del mio errore, è che stamattina ho la mente un po'... appannata.
Grazie della pazienza, come al solito.
nuovoUtente86
17-09-2009, 12:05
Si può sempre fingere che un particolare punto del programma sia il "sistema" - non è detto che sia il main - ma se non è una cosa voluta sin dall'inizio la divisione in oggetti che ne risulta non corrisponderà al fenomeno che il programma rappresenta.
Io ho l' abitudine di veder (o pensare) fin dall' inizio questo punto di accentramento, proprio il cosidetto "sistema" e devo dire di trovarmi bene seguendo questo schema, fermo restando di utilizzare tutti gli strumenti astratti(pattern ad esempio) e offerti dal linguaggio di turno per mantenere il coupling più basso possibile. Magari, è una logica "progettuale" che qualcuno può criticare o non condividere però non credo sia del tutto errata, anzi può rappresentare una buona linea guida oltre che, forse, una semplificazione.
Ikon O'Cluster
18-09-2009, 00:49
Ok la discussione filosofica in sé per sé è interessante nella problematica... ma a tratti prende la piega di sega mentale o sbaglio??? ;)
nuovoUtente86
18-09-2009, 00:59
Ok la discussione filosofica in sé per sé è interessante nella problematica... ma a tratti prende la piega di sega mentale o sbaglio??? ;)
Visto dalla parte della POO e quindi della realizzazione di un ottimo software anche "modulare" e riutilizzabile. direi di SI.
Dal lato filosofico è molto interessante.
banryu79
18-09-2009, 08:30
Ok la discussione filosofica in sé per sé è interessante nella problematica... ma a tratti prende la piega di sega mentale o sbaglio??? ;)
Giuro che non capisco lo spirito dietro questo commento tagliente.
Perchè, postata in questi termini, la tua domanda da me non viene interpretata come tale ma come una provocazione, e, quello che non capisco, è il motivo che ti spinge a provocare.
Se non posso, usando la tua locuzione, "farmi seghe mentali" in una sezione di un forum specificamente dedicata alla "Programmazione" (e sappiamo tutti quanto numerosi siano i campi del sapere indirettamente collegati a questo termine) dove incontro altre persone che possono stimolarmi delle riflessioni che da solo non farei, mi dici dove dovrei andare a farmele, visto che nel mio caso non ho amici che programmano ne colleghi sul lavoro, ma sono solo?
banryu79
18-09-2009, 08:40
Visto dalla parte della POO e quindi della realizzazione di un ottimo software anche "modulare" e riutilizzabile. direi di SI.
Dal lato filosofico è molto interessante.
E invece è proprio vista da questa parte che hai indicato che mi sembra molto pertinente: è proprio la consapevolezza (e quindi la distinzione) di cosa è definizione autonoma e di cosa è "solo" definizione in un sistema osservato dalla prospettiva orientata agli oggetti che mi può aiutare a discriminare, suddividere, progettare il modello di riferimento del fenomeno da rappresentare in modo più aderente alle specifche (che saltano fuori dallo studio del sistema, di business e poi IT).
Magari riuscendo anche a distinguere bene le parti immutabili da quelle mutabili, con tutte le conseguenza che questo comporta per lo sviluppo dell'implementazione, data la natura iterativa dello stesso, come già detto sopra.
E proprio in vista degli interventi manutentivi futuri al primo rilascio: quindi direi che per la realizzazione di "un ottimo software modulare e riutilizzabile" centra parecchio, almeno questo è quello che penso io.
nuovoUtente86
18-09-2009, 11:27
E invece è proprio vista da questa parte che hai indicato che mi sembra molto pertinente: è proprio la consapevolezza (e quindi la distinzione) di cosa è definizione autonoma e di cosa è "solo" definizione in un sistema osservato dalla prospettiva orientata agli oggetti che mi può aiutare a discriminare, suddividere, progettare il modello di riferimento del fenomeno da rappresentare in modo più aderente alle specifche (che saltano fuori dallo studio del sistema, di business e poi IT).
Magari riuscendo anche a distinguere bene le parti immutabili da quelle mutabili, con tutte le conseguenza che questo comporta per lo sviluppo dell'implementazione, data la natura iterativa dello stesso, come già detto sopra.
E proprio in vista degli interventi manutentivi futuri al primo rilascio: quindi direi che per la realizzazione di "un ottimo software modulare e riutilizzabile" centra parecchio, almeno questo è quello che penso io.
Ma non mi riferivo al discorso nella sua globalità (o meglio nella globalità del suo significato)che è intriso di principi cardini per l' orientamento ad oggetti, ma piuttosto (come penso anche chi ha fatto notare la cosa)ad andare a cercare il "pelo nell' uovo" (per carità lo faccio io per primo)su alcune definizioni teoriche piuttosto che altre che hai fini prettamente pratici dello sviluppo del software non spostano gli equilibri.Anche perchè nel software ad oggetti, creato, quasi sicuramente ti ritroverai una marea di oggetti non autonomi, magari non immutabili(lato definizione) ed alta accoppiati, vuoi per pigrizia o perchè in quel momento era conveniente (certo sarebbe meglio evitare) eppure il programma il suo sporco lavoro lo fa bene.
banryu79
18-09-2009, 12:01
Ma non mi riferivo al discorso nella sua globalità (o meglio nella globalità del suo significato)che è intriso di principi cardini per l' orientamento ad oggetti, ma piuttosto (come penso anche chi ha fatto notare la cosa)ad andare a cercare il "pelo nell' uovo" (per carità lo faccio io per primo)su alcune definizioni teoriche piuttosto che altre
Definizioni oggettivamente precise servono ai diversi interlocutori per comunicare in modo chiaro, non solo, sono proprio necessarie quando si sta analizzando una teoria.
...vuoi per pigrizia o perchè in quel momento era conveniente (certo sarebbe meglio evitare) eppure il programma il suo sporco lavoro lo fa bene.
Oltre alla pigrizia e alla convenienza, aggiungici pure anche l'ignoranza, che delle tre è la peggiore perchè a priori rende impossibile operare una scelta, mentre con le altre due una scelta almeno è stata fatta.
Questa considerazione però non centra nulla con la teoria della prospettiva orientata agli oggetti :)
nuovoUtente86
18-09-2009, 12:38
Forse non sono riuscito ad esprimere bene il mio parere rispetto all' utente che affermava come la discussione stesse scadendo nelle "pippe mentali".
Penso che la questione stia nel mezzo: la discussione, anche filosofica se si vuole, su una prospettiva prettamente teorica è importantissima a gettare le basi per lo sviluppo delle attitudini pratiche (che sfocia nel progetto e codifica di un software OO), ma l' accanirsi su determinati concetti forse diventa troppo soprattutto se consideriamo il luogo in cui ci troviamo: un forum forse è il posto dove nell' immediatezza si cerca la soluzione più pratica che teorica.
banryu79
18-09-2009, 13:24
ma l' accanirsi su determinati concetti forse diventa troppo soprattutto se consideriamo il luogo in cui ci troviamo: un forum forse è il posto dove nell' immediatezza si cerca la soluzione più pratica che teorica.
Su questo concordo con te, ma penso che al massimo abbiamo peccato di off topic (e succede spesso, è vero).
C'è anche da dire che l'eventuale off topic si è sviluppato solo dopo che la risposta alla domanda iniziale della'autore del thread era stata bene soddisfatta: quindi non vedo che male c'è.
Se il commento sulle "pippe mentali" dietro aveva questo spirito, ok, ma non ne posso essere sicuro finchè non lo dice Ikon O'Cluster stesso; purtroppo la parola scritta non porta con se tante informazioni sull'intenzionalità di chi la produce quanto la parola parlata, percui spesso è meglio essere un po' più polissi ma chiari.
Ikon O'Cluster
18-09-2009, 21:04
la tua domanda da me non viene interpretata come tale ma come una provocazione, e, quello che non capisco, è il motivo che ti spinge a provocare.
Miiiii come siamo permalooooOOOooosi! :D Dai che era una battuta... alla fine il tuo discorso è valido e interessante. Nella pratica spesso tutta la filosofia si perde, lasciando il programmatore a spalare sterco. Alla fine la teoria è un punto ideale al quale avvicinarsi. Alla latente impossibilità di realizzare praticamente quanto teorizzato, nei progetti più complessi (malgrado gli strumenti e malgrado sforzi organizzativi anche ai più alti livelli) l'azione di più persone, semmai spalmate anche in intervalli temporali molto distanti, tende ad allontanare sempre di più l'utopia di un codice progettato alla perfezione. Alla fine le finezze frutto delle più sagaci scelte progettuali vanno sempre a piegarsi ai vincoli che si generano durante lo sviluppo e a volte ci si ritrova a ristrutturare il progetto. Quindi è bella la filosofia, ma non sono tutte rose e fiori presto servirà una pala... e giù tutti a spalare allegramente. Tutto qua. Inutile scaldarsi.
un forum forse è il posto dove nell' immediatezza si cerca la soluzione più pratica che teorica.
Quoto sinceramente e penso che mi atterrò a questa regola da ora in avanti. Per rassegnazione.
Quoto sinceramente e penso che mi atterrò a questa regola da ora in avanti. Per rassegnazione.
Con me sentiti libero di esprimerti libreramente coi tuoi saggi post :D
(della serie: "l'occasione fà l'uomo ladro")
nuovoUtente86
19-09-2009, 23:28
Quoto sinceramente e penso che mi atterrò a questa regola da ora in avanti. Per rassegnazione.
Quoto la tua rassegnazione, anzi non vorrei che tu avessi frainteso il mio intervento, che era in risposta all' utente ma per nulla contro il voler "teorizzare" che è cosa molto importante.
nuovoUtente86
19-09-2009, 23:28
Con me sentiti libero di esprimerti libreramente coi tuoi saggi post :D
(della serie: "l'occasione fà l'uomo ladro")
giusto
banryu79
21-09-2009, 08:13
Miiiii come siamo permalooooOOOooosi! :D
Ad onor del vero ammetto che quando ho letto e risposto al tuo messaggio ero a corto di sonno e irritato, da cui l'interpretazione da me data al tuo breve messaggio.
Ma non si trattava di permalosità, bensì rabbia nel constatare come con un singolo, poco circostanziato messaggio, si stesse mandando in vacca una discussione interessantissima.
Comunque pace :)
Alla fine le finezze frutto delle più sagaci scelte progettuali vanno sempre a piegarsi ai vincoli che si generano durante lo sviluppo e a volte ci si ritrova a ristrutturare il progetto. Quindi è bella la filosofia, ma non sono tutte rose e fiori presto servirà una pala... e giù tutti a spalare allegramente. Tutto qua. Inutile scaldarsi.
Questo lo capisco perfettamente, ma la "sete di sapere" va oltre quelle che possono essere le esigenze delle realtà lavorative.
Ripeto: si stava parlando di teoria, e se fossero state cose che si possono benissmo leggere altrove, passi, ma la teoria presentata da PGI sull'orientamento agli oggetti non la trovi in qualche testo stampato, da cui la mia curiosità.
Ciao :)
Ikon O'Cluster
21-09-2009, 20:15
Comunque pace :)
Perchè cosa era successo? :D
banryu79
22-09-2009, 08:07
Perchè cosa era successo? :D
Niente, ma non conoscedoti preferisco esplicitare che non ce l'ho con te (potrebbe anche non fregartene una beneamata, in effetti), tutto qua.
Ikon O'Cluster
22-09-2009, 13:16
Tranquillo ;) ciao!
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.