View Full Version : limitare il numero di instanze di una classe
DarkSiDE
18-04-2006, 22:21
è una domanda di teoria, non si riferisce ad un linguaggio specifico
se volessi limitare il numero delle istanze di una classe cosa mi converebbe fare?
vi sembra una 'buona' soluzione questa?
public class MyClass {
private static int instanze=0;
MyClass(){
if (instanze < numero)
instanze++;
else throw new Exception();
}
}
fbcyborg
18-04-2006, 23:13
Guarda.. al momento a me non viene in mente una soluzione definitiva anche se a primo impatto direi che bisognerebbe fare un giro nell'Heap e contare le istanze di questa classe di cui vuoi limitare le istanze. Nel senso: per ogni classe nell'Heap che equivale a MyClass incrementa il contatore... Per verificare se una classe è istanza di MyClass puoi usare istanceOf() oppure isInstance(Object obj) di Class.
Per esempio nella forma:
if ( Class.forName ( classNameString ).isInstance ( myObject ) ) ...
oppure:
Oggetto o = new Oggetto(); if (o instanceof MyClass) ...
Questo controllo nell'heap lo farei ogni volta prima di creare una nuova istanza di MyClass.. e se è stato raggiunto il numero massimo non la creo. Ora però non so se si possa fare questo "giro" nella memoria heap.
Onestamente penso che l'esempio da te riportato sia un po' scorretto. Intanto.. come fa ogni classe a incremetare un contatore "generale" se esso si trova all'interno della stessa?
Quel contatore non diventerà mai maggiore di 1, perchè ogni volta che si chiama il costruttore quello vede che la condizione nell'if è verificata e incrementa, e crea l'oggetto. Poi se ci sono altre invocazioni di quella classe/oggetto, verrà creato un nuovo contatore, anche se a dire il vero essendo statico potrebbe essere modificato da altre classi... ma a questo punto dovrebbe essere anche pubblica la variabile.. non so.. è un po' strano quello che hai scritto.. poi questo blocco:
if (instanze < numero)
instanze++;
else throw new Exception();
io lo metterei più in una classe chiamante (quella che creerebbe l'oggetto MyClass) piuttosto che nel costruttore della stessa...
Non so... contraddicimi pure.. nella confusione sono riuscito solo a fre queste deduzioni e ragionamenti che in parte saranno anche sbagliati.. spero ti aiutino a ragionarci su però.
EDIT: cmq... il fatto che java impedisca di accedere alla memoria penso che inibisca anche la possibilità di vedere quali e quante istanze ci siano in memoria di una certa classe. L'unico sistema è contarle ogni volta che vengono invocate. Per esempio:
variabile statica come contatore; allo scatenarsi di un evento (non so pressione di un pulsante per esempio) verifico il contatore, se esso è inferiore a un certo valore, creo un nuovo oggetto e incremento il contatore, altrimenti lancio eccezione.
ciaoo!
Il codice di DarkSide non fa una grinza (salvo un throws Exception omesso nel costruttore).
Poichè non tutti le lingue che usano costruttori stabiliscono che i costruttori restituiscano istanze (uno di quelli che non lo fa è proprio Java), opterei per un pattern factory (qualcuno diverso da MyClass genera istanze di MyClass), anche per poter decidere la politica di intervento in caso di raggiungimento del limite. Tanto per lasciare la porta aperta perchè l'uso dell'eccezione è in sè, scusa il gioco di parole, ineccepibile.
Io non mi incartapecorirei nella memoria della JVM, cosa pure possibile a partire da Java 5 con JMX.
BountyKiller
19-04-2006, 07:43
i dati membro statici vanno inizializzati al di fuori della classe con l'operatore di risoluzione di scope altrimenti non servono a niente ;)
i dati membro statici vanno inizializzati al di fuori della classe con l'operatore di risoluzione di scope altrimenti non servono a niente ;) :mbe: E dove sta scritto!??
Credo che basti estendere (modificare) correttamente questo pattern (http://en.wikipedia.org/wiki/Singleton_pattern).
è una domanda di teoria, non si riferisce ad un linguaggio specifico
se volessi limitare il numero delle istanze di una classe cosa mi converebbe fare?
vi sembra una 'buona' soluzione questa?
public class MyClass {
private static int instanze=0;
MyClass(){
if (instanze < numero)
instanze++;
else throw new Exception();
}
}
Non vorrei dire una cacchiata ma cosi facendo ti ritroveresti ad avere n classi "MyClass" con l'intero "istanze" settato a 1. ;)
fbcyborg
19-04-2006, 09:00
Non vorrei dire una cacchiata ma cosi facendo ti ritroveresti ad avere n classi "MyClass" con l'intero "istanze" settato a 1. ;)
Appunto! è quello che pensavo anche io! :confused:
come fa a "non fare una grinza" ?
[...]
Quel contatore non diventerà mai maggiore di 1, perchè ogni volta che si chiama il costruttore [...]
è una domanda di teoria, non si riferisce ad un linguaggio specifico
se volessi limitare il numero delle istanze di una classe cosa mi converebbe fare?
vi sembra una 'buona' soluzione questa?
public class MyClass {
private static int instanze=0;
MyClass(){
if (instanze < numero)
instanze++;
else throw new Exception();
}
}
Il tuo codice può anche andare bene, a patto che tu intenda limitare il numero di istanze costruite. Se invece intendi limitare il numero di istanze contemporaneamente esistenti in un dato istante ti conviene pensare al concetto di pooling. Esistono tanti modi per metterlo in pratica, ad esempio se sovrascrivessi nella tua classe il metodo:
public void finalize() throws Throwable {
istanze--;
}
Il grosso difetto del tuo codice è che non è thread-safe: e se ti stai chiedendo "che me ne frega del thread-safe?" allora perchè non delegare all'unico thread che utilizza MyClass il controllo sul numero di istanze?
Un esempio di pooling lo trovi qui (http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/ThreadPoolExecutor.html) .
è una domanda di teoria, non si riferisce ad un linguaggio specifico
se volessi limitare il numero delle istanze di una classe cosa mi converebbe fare?
vi sembra una 'buona' soluzione questa?
public class MyClass {
private static int instanze=0;
MyClass(){
if (instanze < numero)
instanze++;
else throw new Exception();
}
}
La soluzione migliore dipende fortemente da quello che vuoi fare. Spesso e volentieri la soluzione migliore e' non limitare il numero di istanze, oppure passi attraverso un Factory method e rendi il costruttore privato.
Che cosa devi fare di preciso? Devi limitare ad una sola istanza? Devi avere non piu' di un certo numero di istanze vive e riciclarle?
DarkSiDE
19-04-2006, 10:30
raga, attenzione eh:
è una domanda di teoria, non si riferisce ad un linguaggio specifico
raga, attenzione eh:
Allora l'unica risposta e': dipende.
BountyKiller
19-04-2006, 12:48
:mbe: E dove sta scritto!??
da qualche parte nella mia mente :) ma se ci pensi un attimo penso che potrai convenire con me.... il problema di andare a inizializzare un membro statico dentro alla classe che lo possiede è il fatto che tutte le istanze di quella classe fanno quell'inizializzazione e così perdi la "memoria " del membro statico......attenzione che ho scritto inizializzare......se una classe modifica (attenzione: modifica, con un incremento prefisso se il membro è un numero intero,ad esempio) un suo dato membro statico non posso dire a priori che sia sbagliato....... :)
DarkSiDE
19-04-2006, 12:50
Allora l'unica risposta e': dipende.
è una domanda 'generica', una risposta 'generica' va bene :D
Insisto col factory :D.
Vuoi creare degli oggetti, affidi il compito a qualcuno e poichè quel qualcuno li crea può anche contare quanti ne abbia creati. Che io sappia non c'è un linguaggio sedicente orientato agli oggetti che impedisca la definizione di un produttore di altri oggetti. Devo però ammettere di conoscere solo alcuni linguaggi di programmazione e non tutti: magari qualcuno esclude la possibilità di usare il pattern factory.
OT: Le variabili di classe sono create e inizializzate una sola volta, all'atto della preparazione della classe o interfaccia (JLS, 3a ed., 4.12.3, 12.3.2)
In effetti non funziona in quel modo.
Ogni oggetto MyClass in quel modo ha il suo intero "instanze", che ovviamente sarà sempre fisso ad 1.
Si dovrebbe risolvere mettendo fuori dalla classe la variabile in modo che per qualsiasi oggetto MyClass vede quella.
Quindi mettere MyClass dentro un'altra classe.. sbaglio? se si, dove? :)
OT: Le variabili di classe sono create e inizializzate una sola volta, all'atto della preparazione della classe o interfaccia (JLS, 3a ed., 4.12.3, 12.3.2)
Quindi quello che ho scritto su è sbagliato??
Ahhh! comincio a fare confusione..
Usciamo dal seminato perchè la domanda è "in generale" ma visto che c'è la curiosità di saperlo...
Se "istanze" è una variabile di classe, allora esiste una sola variabile "istanze" per l'unica MyClass, per ogni ClassLoader.
Lasciando da parte i ClassLoader, tutte le istanze di MyClass (ma non solo) condividono la stessa variabile "istanze". Le operazioni che un'istanza di MyClass conduca su quella variabile "istanze" saranno visibili ad ogni altra istanza di MyClass.
A scanso d'equivoci, questo non vuol dire che in Java le informazioni si condividano tra oggetti così (o necessariamente così). E' di gran lunga più comune che la condivisione sia mediata da un terzo oggetto, noto ad entrambi i condividenti. Esiste però anche questa possibilità in forza della quale ogni classe Java è potenzialmente un singleton.
Usciamo dal seminato perchè la domanda è "in generale" ma visto che c'è la curiosità di saperlo...
Se "istanze" è una variabile di classe, allora esiste una sola variabile "istanze" per l'unica MyClass, per ogni ClassLoader.
Lasciando da parte i ClassLoader, tutte le istanze di MyClass (ma non solo) condividono la stessa variabile "istanze". Le operazioni che un'istanza di MyClass conduca su quella variabile "istanze" saranno visibili ad ogni altra istanza di MyClass.
A scanso d'equivoci, questo non vuol dire che in Java le informazioni si condividano tra oggetti così (o necessariamente così). E' di gran lunga più comune che la condivisione sia mediata da un terzo oggetto, noto ad entrambi i condividenti. Esiste però anche questa possibilità in forza della quale ogni classe Java è potenzialmente un singleton.
Quindi in poche parole il codice di darkside in linea generale è esatto..
perchè ogni oggetto MyClass creato incrementerà di 1 "instanze" fino ad arrivare a "numero" e quindi al prossimo tentativo di creazione di un oggetto MyClass avremo indietro l'eccezione.. no?
E in effetti provando funziona...
import poo.inout.*;
public class Test{
private static int istanze=0;
private boolean esisto;
public Test(boolean esisto){
if(istanze<4){
this.esisto=esisto;
istanze++;
}else{
System.out.println("STOP, TROPPE ISTANZE");
System.exit(-1);
}
}
public static void main(String args[]){
int n=Console.readInt("Quante istanze? ");
Test vettore[]=new Test[n];
for(int i=0; i<n; i++){
vettore[i]=new Test(true);
}
System.out.println("OK");
}
}
nb: poo.inout è una libreria per leggere da console... vedi: Console.readInt().
Risultati:
Quante istanze? 3
OK
Premere un tasto per continuare . . .
Quante istanze? 4
OK
Premere un tasto per continuare . . .
Quante istanze? 5
STOP, TROPPE ISTANZE
Premere un tasto per continuare . . . . .
da qualche parte nella mia mente :) ma se ci pensi un attimo penso che potrai convenire con me.... il problema di andare a inizializzare un membro statico dentro alla classe che lo possiede è il fatto che tutte le istanze di quella classe fanno quell'inizializzazione e così perdi la "memoria " del membro statico......No :muro: , se una variabile è dichiarata static, diventa una variabile di classe (invece che di istanza), ovvero appartiene alla classe. Una variabile di classe viene quindi inizializzata 1 sola volta quando la classe viene caricata dalla JVM.
BountyKiller
20-04-2006, 12:43
ma non puoi tirare in ballo la jvm..... Reiser non vuole che ci si riferisca a un particolare linguaggio :cool:
ma non puoi tirare in ballo la jvm..... Reiser non vuole che ci si riferisca a un particolare linguaggio :cool:
Il buon caro DS ha fatto due domande. La seconda è, a quanto sembra, su java.
Risposte finora collezionate, in assenza di altre precisazioni:
1. Applicare il pattern Factory ed eventualmente tecniche di pooling e di sincronizzazione.
2. No, ma può funzionare 'bene' in java a patto che il costruttore venga invocato in un solo thread per volta.
ma non puoi tirare in ballo la jvm..... Reiser non vuole che ci si riferisca a un particolare linguaggio :cool:Ok ... allora chiedo scusa se mi sono intromesso nel 3d.
Comunque, in generale, nei linguaggi ad oggetti come C++, C# e Java, una variabile membro dichiarata static appartiene alla classe e non alle istanze. Questo vuol dire che di quella variabile ne esisterà soltanto una (per quella data classe, ovviamente).
BountyKiller
20-04-2006, 16:26
concordo al 100%, io dicevo solo che proprio perchè un membro statico appartiene a una classe e non alle sue istanze, se la classe stessa la >>>>>>>inizializza<<<<<<<<< tutte le istanze di quella classe sovrascrivono questo membro statico che a quel punto non sa più cosa rappresenti. per questo secondo me non ci sono alternative: >>>>l'inizializzazione<<<<<< dei membri statici va fatta fuori dalla classe in questo modo:
<classe> :: <membro_statico> = .....
tutto qui :p :p
se la classe stessa la >>>>>>>inizializza<<<<<<<<< tutte le istanze di quella classe sovrascrivono la variabile statica che a quel punto non sa più cosa rappresenti. :mbe: Non c'è alcuna "sovrascrizione"!!! Cosa stai dicendo!?
OT.
Non è che i linguaggi di programmazione siano eventi emozionali, soggetti ad interpretazione coram populo :D
Per quanto umanamente è possibile, soggiaciono a regole non ambigue.
In Java, non è certamente possibile inizializzare una variabile al di fuori dell'unità di compilazione in cui si trovi la sua dichiarazione.
Se lo fosse sarebbe il linguaggio Juva o Jova, ma non Java.
Per una variabile di classe, l'unico caso in cui è possibile separare l'inizializzazione dalla dichiarazione è usando un "blank final" e un blocco di inizializzazione statico.
Altrimenti o non compila, perchè la variabile è terminale ma priva di inizializzazione, o non è inizializzazione, perchè la variabile ha già ricevuto un valore. Tertium non datur, dicevano i latini: non c'è un altro caso possibile.
Non è una cosa che determino in seguito all'interpretazione del volo delle rondini o che ho letto nelle interiora di un caprone, squartato alla bisogna. Infatti, di Java tutto si può dire tranne che non sia documentato in modo pienamente accessibile. All'indirizzo che segue è possibile scaricare un bel PDF con le regole del linguaggio.
http://java.sun.com/docs/books/jls/
Si tratta di un mattone illeggibile, se lo si voglia affrontare da capo a piedi. Ma per risolvere curiosità del genere emerso in questa discussione è certo un punto di riferimento invidiabile. Insomma, un classico libro da "cerca nell'indice e via".
Poi, per carità, si può discutere sul significato e sulla determinatezza di quanto afferma chi abbia stabilito cosa voglia dire "linguaggio di programmazione Java": non sono le tavole della legge, possono darsi interpretazioni diverse. Ma almeno abbiamo una base di discussione comune.
Stiwy.NET
26-04-2006, 15:41
è una domanda di teoria, non si riferisce ad un linguaggio specifico
se volessi limitare il numero delle istanze di una classe cosa mi converebbe fare?
vi sembra una 'buona' soluzione questa?
public class MyClass {
private static int instanze=0;
MyClass(){
if (instanze < numero)
instanze++;
else throw new Exception();
}
}
Se ho capito bene il tuo quesito la soluzione con VB.NET (C# o qualsiasi linguaggio del framework) dovrebbe essere piuttosto semplice...
Public Class MyClass
Public Shared Istanze as Integer
Public Sub New
Istanze +=1
If Istanze > 5 Then
'non va bene...
Else
'va bene
End If
End Sub
End Class
Ossia invece di dichiarare la variabile costante, la si dichiara condivisa... chiaramente questo funziona nel caso in cui si voglia limitare il numero di dichiarazioni della classe da un solo programma. Non è possibile, quindi, limitare il numero di dichiarazioni della classe richiamata da più programmi. Per risolvere questa problematica si potrebbero sfruttare le chiavi di registro. Mi spiego meglio: nel new si incrementa il valore di una chiave di registro di windows e nel finalize la si decrementa. Potrebbe causare problemi se il programma che usa la classe si inchiodasse e, quindi, non farebbe mai il decremento di quella variabile.
In realtà dovrebbe esserci anche qualche settaggio nell'assembly della classe. Se non ricordo male un mio collega qualche mese fa mi aveva accennato al fatto che con alcune proprietà settate in modo corretto si potrebbe limitare l'uso di un componente (dll, classe, modulo o intera applicazione) a determinati programmi, o a chi ha la chiave giusta... Su questo discorso però non sono molto preparato e dovrei chiedere ai miei colleghi... (devo farlo?)
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.