PDA

View Full Version : singleton pattern


mad_hhatter
03-08-2007, 12:27
perchè si ricorre al attern singleton invece di usare una classe con soli membri statici? operativamente mi sembra la stessa cosa... o mi sfugge qualcosa?

andbin
03-08-2007, 12:35
perchè si ricorre al attern singleton invece di usare una classe con soli membri statici? operativamente mi sembra la stessa cosa... o mi sfugge qualcosa?No, sono cose diverse. In Java, ad esempio, una classe come java.lang.Math ha il costruttore private e tutti i membri sono static e compiono solo operazioni matematiche. Non viene creata alcuna istanza di Math né all'interno di Math né, ovviamente, all'esterno.

Il pattern singleton prevede che ci sia un metodo statico che ritorna una istanza (l'unica possibile) della classe.

mad_hhatter
03-08-2007, 12:37
No, sono cose diverse. In Java, ad esempio, una classe come java.lang.Math ha il costruttore private e tutti i membri sono static e compiono solo operazioni matematiche. Non viene creata alcuna istanza di Math né all'interno di Math ne, ovviamente, all'esterno.

Il pattern singleton prevede che ci sia un metodo statico che ritorna una istanza (l'unica) della classe.

si lo so bene... la mia domanda, evidentemente espressa male, è:

perchè usare il pattern singleton per fare quello che, se non sto prendendo cantonate, si può fare con una classe con soli membri statici?

cionci
03-08-2007, 12:57
Io il problema non me lo pongo, visto che non mi piacciono sia le classi con soli membri statici che il singleton pattern (tra l'altro l'uso, ma soprattutto l'abuso, è sconsigliato anche da chi l'ha messo su carta).
Comunque prima di tutto ci sono differenze a livello operativo: la classe con i soli metodi statici non ha un costruttore. Si può ovviare a questo mettendo un membro statico di controllo che richiami un membro statico "costruttore", ma crea notevoli ripetizioni nel codice, un codice con troppe ripetizioni non è un buon codice.
Altri dubbi mi vengono dal significato che assume una classe con tutti membri statici...se le critiche mosse al singleton sono quelle di andare a ricreare una sorta di variabile globale quando anche nella programmazione non OO cercavamo di farne il più possibile a meno, le critiche che si possono fare alla classe di metodi statici sono ancora più serie: è la negazione della programmazione OO, in quanto di fatto si buttano dalla finestra le funzioni globali per reintrodurle da sotto la porta :D

mad_hhatter
03-08-2007, 13:10
Io il problema non me lo pongo, visto che non mi piacciono sia le classi con soli membri statici che il singleton pattern (tra l'altro l'uso, ma soprattutto l'abuso, è sconsigliato anche da chi l'ha messo su carta).
Comunque prima di tutto ci sono differenze a livello operativo: la classe con i soli metodi statici non ha un costruttore. Si può ovviare a questo mettendo un membro statico di controllo che richiami un membro statico "costruttore", ma crea notevoli ripetizioni nel codice, un codice con troppe ripetizioni non è un buon codice.
Altri dubbi mi vengono dal significato che assume una classe con tutti membri statici...se le critiche mosse al singleton sono quelle di andare a ricreare una sorta di variabile globale quando anche nella programmazione non OO cercavamo di farne il più possibile a meno, le critiche che si possono fare alla classe di metodi statici sono ancora più serie: è la negazione della programmazione OO, in quanto di fatto si buttano dalla finestra le funzioni globali per reintrodurle da sotto la porta :D

perfettamente d'accordo. ma nei rari casi in cui è necessaria un'entità centralizzata che deve essere accessibile a più entità clienti senza la necessità di passare l'oggetto condiviso come parametro che altre strade hai? una factory ha molti vantaggi a livello di design ed è un singleton, per esempio...

io ritengo che l'abuso di qualsiasi cosa sia dannoso (salvo eccezioni che sarebbero OT :D ), ma l'uso oculato è, per definizione, buona cosa.

Quanto al costruttore: creare un singleton con un parametro di costruzione è una cosa delicata di per sè... comuqnue questa situazione mi pare l'unica in cui un singleton è diverso da una classe con solo membri statici... è corretto?

grazie a tutti per i vostri interventi passati e futuri :)

cionci
03-08-2007, 13:34
perfettamente d'accordo. ma nei rari casi in cui è necessaria un'entità centralizzata che deve essere accessibile a più entità clienti senza la necessità di passare l'oggetto condiviso come parametro che altre strade hai? una factory ha molti vantaggi a livello di design ed è un singleton, per esempio...
Non è detto che debba essere un singleton, se la si astrae debitamente di comporterà come un singleton, ma non lo sarà. Soprattutto non la si rende disponibile ovunque come una variabile globale.
Quanto al costruttore: creare un singleton con un parametro di costruzione è una cosa delicata di per sè... comuqnue questa situazione mi pare l'unica in cui un singleton è diverso da una classe con solo membri statici... è corretto?
Non è tanto il parametro del costruttore il problema, ma se l'oggetto istanziato una sola volta ha necessità di operazioni di inzializzazione.

mad_hhatter
03-08-2007, 13:58
Non è tanto il parametro del costruttore il problema, ma se l'oggetto istanziato una sola volta ha necessità di operazioni di inzializzazione.

un inizializzatore statico non va bene?

cionci
03-08-2007, 14:06
un inizializzatore statico non va bene?
Certo che va bene, ma in ogni altro metodo statico devi controllare se l'inizializzazione è già avvenuta e se non è avvenuta devi chiamare il metodo statico che fa l'inizializzazione.

if(!initDone) doInit();

Il che implica una duplicazione in ogni metodo statico.

mad_hhatter
03-08-2007, 14:10
Certo che va bene, ma in ogni altro metodo statico devi controllare se l'inizializzazione è già avvenuta e se non è avvenuta devi chiamare il metodo statico che fa l'inizializzazione.

if(!initDone) doInit();

Il che implica una duplicazione in ogni metodo statico.

scusa, ma in java c'è il blocco static{} richiamato quando la classe viene caricata, in c# ci sono i costruttori statici... non fanno proprio quello di cui parli?

cionci
03-08-2007, 14:11
scusa, ma in java c'è il blocco static{} richiamato quando la classe viene caricata, in c# ci sono i costruttori statici... non fanno proprio quello di cui parli?
In C++ non c'è niente di tutto questo...facevo riferimento a quello ;)

Ufo13
03-08-2007, 14:22
Odio il singleton pattern, abusato da molti perche` altrimenti non sanno come passare variabili nei metodi.

Si tratta dell'equivalente di scrivere codice C usando variabili globali invece che parametri e questa e` una cosa comunemente riconosciuta come sbagliata.

Il singleton e` piu` accettato, secondo me, perche`:
- E` un pattern quindi usarlo e` bene anche se leggendo i lpattern si son saltate un po` di righe...
- E` object oriented.
- E` sempre meglio che usare variabili globali.

Comunque non so se ti riferisci a Java o C# ma in C++ il singleton viene usato principalmente perche` l'ordine di inizializzazione delle variabili globali e` undefined e se hai singleton che usano altri singleton nel costruttore (oddio!!!) avresti comportamento undefined.

Ultima nota sul singleton pattern: si usa il singleton pattern quando il design esplicitamente richiede che esista UNA SOLA istanza di quell'oggetto e se mai nella vita del progetto dovessero esistere due o piu` istanze questo sarebbe un grave errore.

mad_hhatter
03-08-2007, 14:35
Odio il singleton pattern, abusato da molti perche` altrimenti non sanno come passare variabili nei metodi.

Si tratta dell'equivalente di scrivere codice C usando variabili globali invece che parametri e questa e` una cosa comunemente riconosciuta come sbagliata.

Il singleton e` piu` accettato, secondo me, perche`:
- E` un pattern quindi usarlo e` bene anche se leggendo i lpattern si son saltate un po` di righe...
- E` object oriented.
- E` sempre meglio che usare variabili globali.


il fatto che molti usino male alcuni strumenti non fa di questi strumenti una cosa negativa... il fatto che molti scrivano cattivo codice in un linguaggio X non rende il linguaggio X una schifezza.

Una variabile globale è assolutamente non protetta, un oggetto o una classe permettono l'incapsulamento, non è assolutamente la stessa cosa!

"Generalmente" non significa "sempre" :)

quanto alla tua lista di punti:
- non uso cose perchè altri mi han detto che è bene: voglio sapere SE, QUANDO e PERCHE' è bene (e quali sono i compromessi)... per questo ho aperto il thread chiedendo la differenza tra una classe con membri static e un singleton
- va beh, ma oop è un paradigma, non il dio supremo
- ho già scritto a riguardo poche righe fa


Ultima nota sul singleton pattern: si usa il singleton pattern quando il design esplicitamente richiede che esista UNA SOLA istanza di quell'oggetto e se mai nella vita del progetto dovessero esistere due o piu` istanze questo sarebbe un grave errore.

se non fosse così non starei prendendo in considerazione il singleton pattern :)

PGI-Bis
03-08-2007, 15:31
Una classe con metodi statici genera una dipendenza di definizione che, per l'orientamento agli oggetti, significa che oggetto è l'unione tra la definizione di quella classe e quella della classe utente.

E' corretto quando dici "l'unica differenza mi pare essere quella del costruttore con argomenti" perchè il confronto che fai è tra due forme Java che, sempre dal punto di vista dell'orientamento agli oggetti, generano entrambe dipendenza di definizione. Resta solo il "dettaglio tecnico" del costruttore.

Al bocciofilo si dice che questo sia sbagliato. In verità è una questione di significati. L'orientamento agli oggetti è una prospettiva totalizzante. Non ci sono cose incompatibili con l'orientamento agli oggetti ma semplici alterazioni di significato. Dell'unico significato esistente nell'orientamento agli oggetti, vale a dire cosa sia oggetto e cosa sia parte della definizione di un oggetto.

mad_hhatter
03-08-2007, 15:44
Una classe con metodi statici genera una dipendenza di definizione che, per l'orientamento agli oggetti, significa che oggetto è l'unione tra la definizione di quella classe e quella della classe utente.

E' corretto quando dici "l'unica differenza mi pare essere quella del costruttore con argomenti" perchè il confronto che fai è tra due forme Java che, sempre dal punto di vista dell'orientamento agli oggetti, generano entrambe dipendenza di definizione. Resta solo il "dettaglio tecnico" del costruttore.

Al bocciofilo si dice che questo sia sbagliato. In verità è una questione di significati. L'orientamento agli oggetti è una prospettiva totalizzante. Non ci sono cose incompatibili con l'orientamento agli oggetti ma semplici alterazioni di significato. Dell'unico significato esistente nell'orientamento agli oggetti, vale a dire cosa sia oggetto e cosa sia parte della definizione di un oggetto.

ehm... ti offendi (e io faccio tanto la figura del babbeo) se ti confesso che credo di non aver capito bene?

soprattutto quando parli di dipendenza di definizione

Ufo13
03-08-2007, 17:01
il fatto che molti usino male alcuni strumenti non fa di questi strumenti una cosa negativa... il fatto che molti scrivano cattivo codice in un linguaggio X non rende il linguaggio X una schifezza.

L'uso corretto del singleton e` quello di forzare una sola istanza.

Ricordo in diamonds i test che fallivano senza motivo per colpa del singleton pattern e l'uso oltrettutto era corretto...

Nous
03-08-2007, 17:05
perchè usare il pattern singleton per fare quello che, se non sto prendendo cantonate, si può fare con una classe con soli membri statici?

Una classe con i soli metodi statici è una classe di utilità, che fornisce metodi il cui output dipende solo dall'input fornito e non dallo stato dell'oggetto (che non hai perchè non istanzi la classe). Esempio : un metodo che somma due numeri.

Il pattern singleton lo usi quando vuoi che ci sia una sola istanza di una classe per tutta la durata dell'applicazione, mediamente quando vuoi che ad una risorsa acceda sempre una classe per evitare problemi di concorrenza o di (mancanza di) atomicità sui dati. Esempio : un logger di sistema, ne vuoi uno solo che si occupi di memorizzare gli eventi sul sistema. Hai un'istanza, quindi hai un'oggetto con uno stato e i metodi che fornisce la classe modificano lo stato dell'oggetto (almeno in teoria, in pratica dipende dal tuo modo di vedere la programmazione ad oggetti).

Nous
03-08-2007, 17:06
la classe con i soli metodi statici non ha un costruttore.

Falso, il costrutto di default è sempre implicito. Tant'è che una buona classe di utilità dovrebbe definire esplicitamente il costruttore e con scope privato.

cionci
03-08-2007, 17:14
Falso, il costrutto di default è sempre implicito. Tant'è che una buona classe di utilità dovrebbe definire esplicitamente il costruttore e con scope privato.
Il costruttore di default c'è ma non viene mai utilizzato ;)
Se io uso la classe con i soli metodi statici il costruttore di default non verrà mai chiamato.
Allora mettiamola così: una classe con soli metodi statici non ha un costrutto equivalente al costruttore che permette di inizializzare la classe, almeno in C++ a quanto sembra.

Nous
03-08-2007, 17:16
Il costruttore di default c'è ma non viene mai utilizzato ;)
Se io uso la classe con i soli metodi statici il costruttore di default non verrà mai chiamato.
Allora mettiamola così: una classe con soli metodi statici non ha un costrutto equivalente al costruttore che permette di inizializzare la classe, almeno in C++ a quanto sembra.

Sì ma è istanziabile, provare per credere ;)
E' sbagliato che lo sia...e quindi si deve renderlo non istanziabile :)

cionci
03-08-2007, 17:17
Sì ma è istanziabile, provare per credere ;)
E' sbagliato che lo sia...e quindi si deve renderlo non istanziabile :)
Certo che lo è...vorrei anche vedere...

mad_hhatter
03-08-2007, 17:28
L'uso corretto del singleton e` quello di forzare una sola istanza.

Ricordo in diamonds i test che fallivano senza motivo per colpa del singleton pattern e l'uso oltrettutto era corretto...

quindi l'implementazione era errata

mad_hhatter
03-08-2007, 17:28
Una classe con i soli metodi statici è una classe di utilità, che fornisce metodi il cui output dipende solo dall'input fornito e non dallo stato dell'oggetto (che non hai perchè non istanzi la classe). Esempio : un metodo che somma due numeri.


io ho parlato di membri, non di metodi: una classe può avere campi statici e, quindi, uno stato

Ufo13
03-08-2007, 18:11
quindi l'implementazione era errata

Nessun errore, lo unit testing risulta piu` difficile da implementare e verificare usando singleton.

cionci
03-08-2007, 18:15
Nessun errore, lo unit testing risulta piu` difficile da implementare e verificare usando singleton.
Sì...entrano in gioco problemi legati all'ordine di esecuzione dei test in quanto nonostante le classi oggetto di test vengano istanziate ogni volta per ogni singolo test, i membri statici restano validi fra l'esecuzione di un test e quella del successivo.

mad_hhatter
03-08-2007, 18:26
Nessun errore, lo unit testing risulta piu` difficile da implementare e verificare usando singleton.

ah ok, non avevo capito stessi parlando di unit testing, sorry

PGI-Bis
03-08-2007, 18:39
mad_hhatter, io sono inoffendibile e tu non sei un babbeo.

Hai un problema alla "the matrix". C'è qualcosa che non ti suona bene e cerchi di capire cosa.

La risposta alla tua più che lecita domanda "perchè singleton anzichè metodi statici" è che non c'è differenza. La ragione per cui non c'è differenza sta nella risposta ad un'altra domanda: cos'è un oggetto?

Un oggetto è una definizione autonoma.

Se una definizione non è autonoma allora non è un oggetto. Un esempio di definizione (relativamente) autonoma è:

public class Pluto {}

Pluto è un oggetto.

Un esempio di definizione non autonoma è:

public class Pippo {
private String x;
}

Pippo non è un oggetto: l'oggetto è l'unione delle definizioni di Pippo e String.

Se la domanda "qual'è la differenza tra un singleton e una classe con metodi statici" è riferita al contesto della programmazione orientata agli oggetti allora la risposta non può che essere data nei termini dell'orientamento agli oggetti. Termini che sono... uno solo: oggetto.

Sia nel caso dei metodi statici che nel caso del singleton noi abbiamo che la definizione che ne faccia usa perde autonomia generando un oggetto che è l'unione tra la definizione dipendente e la definizione del singleton/classe con metodi statici.

Non è una questione di verità, di giusto o sbagliato, di (Santa Caterina guidaci) "pattern" e (San Giuseppe aiutaci) "antipattern": è una questione di significati.

mad_hhatter
03-08-2007, 21:44
wow... ho aperto il vaso di Pandora...

premetto che la mia esperienza non e' all'altezza della tua, ma mi permetto di non essere d'accordo con la tua argomentazione. Portandola agli estremi, nulla e' un oggetto: Non appena un'entita' entra in relazione d'usp con un'altra perde autonomia. Non appena un'entita' ne incapsula un'altra perde autonomia... eppure l'incapsulamento e' uno dei cardini dell'orientamento agli oggetti... ma al di la' di cio', secondo quanto dici, un oggetto che non abbia le caratteristiche di assoluto isolamento non e' un oggetto... lo trovo sorprendente come ragionamento.

Ufo13
03-08-2007, 23:36
se i membri sono statici non hai nessun controllo sull'ordine di creazione delle varie istanze (ti parlo di c++).

Con il pattern hai controllo sia su creazione che su distruzione.

Non sono super ferrato in multithreading ma mi pare che gli oggetti statici siano soggetti a diversi problemi in ambienti multithreaded...

PGI-Bis
04-08-2007, 00:56
wow... ho aperto il vaso di Pandora...

L'estremo è molto importante.

Se porti all'estremo la faccenda, cioè se dici che ogni definizione dipende da un'altra definizione, alla fine non ottieni "nessun oggetto": ottieni un solo oggetto.

Se A dipende da B e B dipende da A, A+B non dipende da nulla.

A non è oggetto, B non è oggetto ma A+B sì.

E' una cosa assolutamente affascinante. Anche in un contesto estremo, la definizione di oggetto risulta coerente. Cioè non ti porta a dover ammettere l'esistenza di cose che non sono oggetti.

C'è un'altra cosa che occorre considerare e nota che siamo sempre alla definizione di oggetto, siamo sempre a ciò che è evidente per quelle sei misere parole.

Se Pippo usa String, Pippo non è oggetto perchè la sua definizione non è autonoma. Esiste un oggetto Pippo+String. Ed esiste un secondo oggetto: String. String non dipende da Pippo. Magari dipende da qualcos'altro. E va benissimo. A limite significa che ciò che chiamo String dovrebbe essere String+qualcos'altro.

E' sorprendente la conseguenza. Se String è un oggetto ed è anche parte della definizione di un altro oggetto, allora String io non posso cambiarlo nè eliminarlo. Posso invece cambiare o eliminare Pippo. Detto altrimenti, qualsiasi mutazione di String è rilevante, perchè altera la definizione di un altro oggetto, qualsiasi mutazione di Pippo è irrilevante, perchè non altera la definizione di alcun oggetto. Salvo sè stesso, ma questo è ammesso: definizione autonoma rispetto ad altre, non autonoma anche da sè.

E qui si dovrebbe vedere la viva forza di questo oggetto. Una volta che io ho individuato gli oggetti e stabilito quali di questi siano parte della definizione di altri io so anche cosa posso alterare, fino al limite della completa rimozione, e cosa non posso assolutamente cambiare. O, meglio, cosa succede se cambio o elimino un pezzo del sistema. Succede che ogni definizione dipendende subisce il riflesso di quella mutazione.

Questa reazione alle mutazioni, questa sorta di effetto a catena attivato da una mutazione di definizione è anche ciò che spiega le ragioni dell'incapsulamento.

L'incapsulamento non è un principio dell'orientamento agli oggetti. Il principio dell'orientamento agli oggetti è uno solo, è una definizione, la definizione di oggetto.

L'incapsulamento è una tecnica per controllare il propagarsi delle mutazioni di definizione.

E si sposa benissimo con la definizione di oggetto. Il fatto che un'informazione sia incapsulata o no è irrilevante per l'utente di quell'informazione. E' invece rilevante per le definizioni che dipendono da quella in cui quell'informazione è contenuta. Perchè la mutazione della rappresentazione di ciò che è incapsulato non si propaga alle definizioni dipendenti.

Occorre tuttavia prestare grande attenzione a questa tecnica. Un campo privato è comunque parte di una definizione. Se la mutazione di quel campo coinvolge una parte di definizione non incapsulata, allora quel mutamento è passibile di propagazione alle definizioni dipendenti. Possiamo chiamarla propagazione indiretta ma è comunque un'evidenza:

class Pippo {
private String value;

public String getValue() {
return value;
}
}

"value" è private. Posso cambiarlo in "Integer"? Sì ma lo faccio così:

class Pippo {
private Integer value;

public String getValue() {
return String.valueOf(value);
}
}

Perchè lo faccio così? Perchè non dico "public Integer getValue()"? Perchè, a differenza di value, una mutazione in getValue si propagherebbe. Cambierebbero altre definizioni. Se voglio preservare l'integrità di quelle definizioni, io devo preservare la parte di definizione da cui queste dipendono.

E' una mera questione di cause ed effetti.

Questo è la ragione d'essere dell'incapsulamento. Non si incapsula "perchè è bello, evviva". Lo fai per controllare la quantità di mutazioni riflesse o, vista dall'altro lato, per poter mutare senza coinvolgere altre definizioni (salvo quella che contiene il dato incapsulato).

Riprendi il singleton. Caso "classe con metodi statici" e "classe che restituisce un'instanza privata statica della classe stessa". Se le esamini dal punto di vista di una definizione terza e dipendente noterai come in entrambi i casi essa si trovi a dover dipendere dalla classe del singleton.

Il che non è giusto o sbagliato. Semplicemente ti dice che tutti gli oggetti che usano il singleton lo assumono come parte della propria definizione e che questo ha delle conseguenze nel caso in cui alcune parti del sistema debbano essere cambiate.

Non farti fuorviare dall'apparente stranezza dei termini o dal fatto che, diavolo ma è tutto qui. Sì, è tutto qui. Definizione autonoma. E le conseguenze sono banalissime.

mindwings
04-08-2007, 11:03
@ PGI-Bis Mostro! :D (nel senso buono del termine)
come fai a conoscere tutte queste minuzie?:eek:
dì ma sei stato a cena da Gosling ? :D

mad_hhatter
04-08-2007, 12:14
...

affascinante e molto elegante come ragionamento. Ho capito il tuo punto di vista e mi piacerebbe approfondirlo. Fin'ora ho studiato l'orientaento a oggetti solo dal punto di vista delle sue implementazioni particolari, Java in primis... ora vorrei andare dritto alla "fonte", alle fondamenta teoriche della OOP. Hai qualche testo di riferimento, anche solo un link o un nome da cui posso partire?

grazie mille!

PGI-Bis
04-08-2007, 14:12
Prima di tutto, esaminate con severo occhio critico quanto ho detto. Una stupidaggine è una stupidaggine. Se viene da un premio nobel è al più un'autorevole stupidaggine.

Ciò detto, non ho testi, riferimenti o link. Non c'è un libro sull'orientamento agli oggetti.

Ci sono quelli sulle lingue ma, come dice mad_hatter, i linguaggi sono una conseguenza. E' Java a pretendere di essere orientato agli oggetti e non l'orientamento agli oggetti ad essere Java. O C++ o Smalltalk.

Insomma, bisogna stare attenti a non forzare la programmazione orientata agli oggetti nelle caratteristiche di un linguaggio. Il fatto che C++ abbia le classi non significa di per sè che le classi siano una colonna dell'OOP.

Io penso che si debba partire dalle ragioni che hanno portato alla creazione dell'OOP. Dal perchè dell'OOP.

Si tratta, cioè, di iniziare rispondendo ai dubbi più elementari che possono sorgere nel momento in cui si propone l'orientamento agli oggetti come prospettiva applicata alla programmazione.

Proporre l'idea che un oggetto sia una definizione autonoma non è un moto d'impeto, un coniglio tirato fuori dal cappello.

Nasce dall'interpretazione di cosa è necessario che sia affinchè un essere umano possa acquisire consapevolezza di un fenomeno, reale o immaginario.

Assumere la percezione umana dei fenomeni come "motivo" dell'orientamento agli oggetti è ciò che in senso assoluto permette di predicarne il vantaggio rispetto ad altre prospettive.

Questi sono tuttavia discorsi preliminari. Teorici, se vogliamo. All'atto pratico è il fatto di considerare il mio programma come un insieme di definizioni autonome che mi permette di capire se quello che ho scritto corrisponde o non corrisponde a quello che ho inteso rappresentare.

E' importante comunque tenere presente che non esiste una buona programmazione orientata agli oggetti ed una cattiva programmazione orientata agli oggetti.

Ciò che esiste o non esiste è una corrispondenza tra quello che risulta dall'interpretazione orientata agli oggetti del codice che ho scritto e il sistema di riferimento, cioè quello che avrei voluto scrivere.

Se il sistema di riferimento prevede l'esistenza di un oggetto A e un oggetto B e il codice dice che A e B sono reciprocamente dipendenti allora quello che ho scritto non coincide con quello che ho "progettato". E' facile intendere le conseguenze di questa mancata corrispondenza. Io so che un oggetto è ridefinibile se non è parte della definizione di un altro oggetto. Se il progetto qualifica B come ridefinibile e il codice no, le mutazioni di B avranno effetti diversi da quelli che ci si attenderebbe. Questo non perchè io abbia esercitato una "cattiva" programmazione orientata agli oggetti ma perchè, molto più semplicemente, il programma ed il progetto non coincidono.

marco.r
04-08-2007, 16:51
In C++ non c'è niente di tutto questo...facevo riferimento a quello ;)
Volendo si può usare una funzione inizializzando una variabile globale. In questo modo l'inizializzazione viene eseguita a tempo di caricamento dell'unità di compilazione. Ovviamente la cosa funziona se l'inizializzazione non prevede l'uso di oggetti/funzioni presenti in altre unità di compilazione e inizializzate in modo analogo (visto che l'ordine in cui questo viene fatto è indefinito)

Nous
06-08-2007, 08:59
io ho parlato di membri, non di metodi: una classe può avere campi statici e, quindi, uno stato

Lo stato è relativo agli oggetti istanza della classe, non alla classe.
Una classe non ha uno stato, lo stato è dato dagli attributi di istanza.

Nous
06-08-2007, 09:07
wow... ho aperto il vaso di Pandora...

premetto che la mia esperienza non e' all'altezza della tua, ma mi permetto di non essere d'accordo con la tua argomentazione. Portandola agli estremi, nulla e' un oggetto: Non appena un'entita' entra in relazione d'usp con un'altra perde autonomia. Non appena un'entita' ne incapsula un'altra perde autonomia... eppure l'incapsulamento e' uno dei cardini dell'orientamento agli oggetti... ma al di la' di cio', secondo quanto dici, un oggetto che non abbia le caratteristiche di assoluto isolamento non e' un oggetto... lo trovo sorprendente come ragionamento.

La progettazione ad oggetti studia gli oggetti e le interazioni tra gli oggetti, non capisco la tua osservazione...al di là del fatto che entità è un termine impreciso, che nella modellazione ad oggetti si applica solo agli oggetti persistenti (ossia a quelli che persistono un modello E-R).
Attenzione all'isolamento, si finisce nell'antipattern "ravioli code" ;)

Per risponderti in maniera più esaustiva, tra i pattern basilari ce ne sono due che devono essere rispettati nella maniera più assoluta :
1) alta coesione ;
2) basso accoppiamento.

Basso accoppiamento vuol dire che un oggetto deve avere relazioni solo con quello che effettivamente gli serve per svolgere al meglio le sue funzioni.
Alta coesione vuol dire che l'oggetto deve essere specializzato, se nell'applicazione si deve scrivere su base dati ci sarà un solo oggetto (specialista) che lo farà, non 100 oggettini che scrivono indipendentemente.

Questo per massimizzare la riusabilità, la manutenibilità, la resistenza, ... e tutte le caratteristiche che l'ing. del software attribuisce ad un software di qualità.

Nous
06-08-2007, 09:15
Questo è la ragione d'essere dell'incapsulamento. Non si incapsula "perchè è bello, evviva". Lo fai per controllare la quantità di mutazioni riflesse o, vista dall'altro lato, per poter mutare senza coinvolgere altre definizioni (salvo quella che contiene il dato incapsulato).


L'incapsulamento ha senso anche nel contesto del pattern "Don't talk to strangers" : immaginiamo di avere classe A (oggetto a) associata a classe B (oggetto istanza di B : b) e C (c), c vuole accedere ad un metodo b() di b, e per farlo vorrebbe passare da a. Non è corretto scrivere (da c) a.b.b(), perchè alza l'accoppiamento (che deve essere basso).
La soluzione è che a fornisca un metodo b() di accesso all'omonimo metodo dell'oggetto b di intermediazione.
Quindi c scriverà solo a.b().

PGI-Bis
06-08-2007, 11:39
Perchè l'accoppiamento deve essere basso?

Nous
06-08-2007, 11:54
Perchè l'accoppiamento deve essere basso?

Per rendere facilmente gestibili gli interventi di manutenzione perfettiva, manutentiva o correttiva...se modifichi una classe che è associata a decine di altre classi, l'intervento si propagherà su tutte le classi con cui è associata.
Questo ovviamente rende il sofware più robusto di fronte al cambiamento... perchè è più facile prevedere errori dovuti a qualche modifica di una classe ed al contempo è più difficile farne.
Tant'è che un buon design è un design che non ha troppe associazioni, c'è pure una metrica di valutazione del codice che conta (fisicamente) le associazioni tra le classi (sul diagramma UML).

PGI-Bis
06-08-2007, 12:09
Dunque l'accoppiamento è irrilevante ogni volta in cui io non abbia interesse ad intervenire sull'oggetto?

Intendo "per assurdo", o "all'estremo", se vogliamo.

Se per assurdo io avessi la certezza che un certo pezzo del sistema non cambierà mai, proprio mai, allora l'accoppiamento, cioè le associazioni tra il resto del sistema e quel pezzo, vale a dire la presenza di un collegamento "immutabile" tra le altre parti del sistema e quella chimera, sarebbe irrilevante.

E' corretto?

Nous
06-08-2007, 12:22
Tieni presente che di solito se hai una classe che ha decine di accoppiamenti (beata lei :oink: ) questo vuol dire che hai progettato male il sistema, non dovrebbe mai succedere. Senza contare che al codice una mano ogni tanto ce la dovresti sempre passare, per un pò di sano refactoring...comunque niente ti obbliga a seguire i Patterns GOF, non sono imperativi ma solo suggerimenti ;)

Comunque...per rispondere alla tua domanda...se la tua chimera è immutabile dovrebbe anche essere isolata dall'universo, perchè se cambiasse una relazione tra lei ed un'altra classe potrebbe succedere che la cosa si propaghi a tutte le classi. Esempio : classe "chimera" che fornisce (tra le altre cose) un metodo di intemediazione versi una classe la quale però viene modificata. La classe "chimera" non è toccata, ma risente della modifica e parimenti tutte le classi che sono associate alla "chimera".

PGI-Bis
06-08-2007, 13:01
Il mio tentativo è quello di superare i "buoni principi" ed arrivare ad una sistemazione generale dell'orientamento agli oggetti. Generale nel senso che fornisca principi sempre validi. Sempre valido significa mai eccepito.

Un oggetto indipendente non è necessariamente isolato.

Scusate il gioco di parole, dipende dalla definizione di dipendenza.

Se dipendente è una definizione alterabile dalla mutazione di un'altra definizione, allora è indipendente quella definizione che non ne richieda altre.

Se io posso dare una definizione di intero che non dipende da String allora intero è indipendente da String.

Se la definizione di intero è anche immutabile allora il principio del basso accoppiamento, che ha le sue ragioni nel permettere di "cambiare le carte in tavola", cessa di avere significato.

Cioè vale solo se una cosa è destinata a cambiare.

Si intuisce il problema? Se il basso accoppiamento è un principio dell'orientamento agli oggetti, ciò per cui l'accoppiamento è irrilevante cessa di essere orientato agli oggetti? Se non è orientato agli oggetti, cos'è? E se scrivessi un sistema in cui tutte le definizioni sono immutabili?

Nous
06-08-2007, 13:20
Cioè vale solo se una cosa è destinata a cambiare.


Non dimenticare che tutto cambia, a partire dalle specifiche di progetto fino alle implementazioni...il cambiamento è uno dei massimi problemi dell'ing. del software, e l'applicazione di alcuni semplici pattern ne minimizza la gestione. Meglio ancora se si utilizzano metodi di sviluppo agili, ma qui andiamo proprio OT e quindi evito ;)

PGI-Bis
06-08-2007, 14:02
Non saresti OT. Pattern e sviluppo agile sono accomunati dalla stessa carenza di fondamento.

Non possiamo risolvere la cosa dicendo che tutto cambia. Dobbiamo trovare un sistema che sia dimostrabilmente valido sia per ciò che cambia che per ciò che non cambia.

Io credo fermamente che la ragione per cui l'orientamento agli oggetti è considerato pratica esoterica stia nel cumulo di "best practices" che, negli anni, vi sono state riversate.

Il problema dell'accoppiamento che hai sollevato non è assolutamente pellegrino ed è strettamente collegato all'immutabilità.

L'estremo dell'accoppiamento lo abbiamo non quando le dipendenze siano molte ma quando noi consideriamo la dipendenza come una relazione reciproca.

Cioè se A dipende da B allora necessariamente B dipende da A. Se:

Pippo
+String

allora non solo Pippo->String ma anche String->Pippo.

Che è quasi intuitivo. Se pippo dipende da String allora un tipo particolare di mutazione di String, cioè la sua eliminazione, è impedita dall'invalidità riflessa sulla definizione di Pippo. A fronte di una definizione reciproca di dipendenza e rispetto all'eliminazione, la definizione di String cessa di essere autonoma.

La faccio breve intesa come rapporto reciproco, la dipendenza conduce al "bizzarro": non esiste orientamento "agli oggetti" ma solo orientamento "all'oggetto". Cioè tutti i sistemi si risolvono in un unico oggetto.

Teoricamente è possibile ma operativamente è una struffolata. Qualsiasi cosa io cambi avrà un effetto limitato agli oggetti che usano quell'oggetto come parte della loro definizione. Cioè l'oggetto stesso, vale a dire tutto quanto il sistema.

Per poter rendere utile questa visione dell'orientamento agli oggetti io devo introdurre il concetto di "immutabilità" nella dipendenza.

Se io potessi considerare immutabili alcune definizioni autonome (cioè alcuni oggetti) e se io definissi la dipendenza come una mutazione riflessa subita per effetto di un cambiamento in una definizione esterna, allora potrei dire che un oggetto immutabile (cioè una definizione immutabile) non genera dipendenza.

Il fatto che una definizione immutabili non generi dipendenza è praticamente utile, e parecchio, perchè io so di poter manipolare all'estremo (cioè fino all'eliminazione totale) tutte le definizioni che includono l'oggetto immutabile come parte di sè. So inoltre che, nel mio sistema, dovrei considerare assolutamente intoccabili (immodificabili ed ineliminabili) tutte le definizioni dichiarate immutabili.

E' una strada intrigante.

Ps.: forse non l'ho detto ma la faccenda dell'autonomia, cioè il fatto che una definizione debba essere autonoma per poter essere oggetto, è una necessità logica, dimostrabile per assurdo. E' un principio di conoscibilità: se una definizione non è autonoma allora ciò che definisce non è conoscibile, se non esistesse autonomia allora non esisterebbe la conoscenza in assoluto.