Monostate vs. Singleton

Quali sono gli scenari in cui si utilizza un pattern Monostate al posto di singleton per mantenere un object globale?

Edit: So quali sono i pattern Singleton e Monostate. Ho anche implementato Singleton in diversi scenari. Voglio solo conoscere gli scenari (esempi di casi) in cui il modello di MonoState deve essere implementato.

Per es. Ho bisogno di mantenere l’elenco delle colonne per schermo nella mia app di Windows Form. Potrei usare un dizionario Singleton in questo caso. Tuttavia, sto memorizzando una lista nella variabile statica globale e volevo fornire gli indicizzatori (poiché ho bisogno di aggiungere dynamicmente una nuova voce alla lista se la chiave non è presente) dove potrei specificare ScreenDetails.ScreenName come chiave e ottenere gli ScreenDetails .ColumnsTable. Poiché gli indicizzatori non possono operare su una class statica, ho modificato il pattern in Monostate.

Quindi vorrei sapere quali altri scenari possono obbligare un utente a usare Monostate invece di Singletons.

Alla base, Monostate è solo zucchero sintattico attorno a Singleton. Dove la Monostazione diventa interessante è quando inizi la sottoclass, perché le sottoclassi possono decorare lo stato condiviso con un comportamento diverso.

Un semplice – se un po ‘artificioso e poco efficiente 🙂 – esempio:

public class GlobalTable implements Iterable { /** Shared state -- private */ private static final Map MAP = new LinkedHashMap(); /** Public final accessor */ public final Value get(Key key) { return MAP.get(key); } /** Public final accessor */ public final boolean put(Key key, Value value) { return MAP.put(key); } /** Protected final accessor -- subclasss can use this to access the internal shared state */ protected final Set keySet() { return MAP.keySet(); } /** Virtual -- subclasss can override for different behavior */ public Iterator iterator() { return Collections.unmodifiableSet(MAP.keySet()).iterator(); } } 

Ora, cosa succede se vogliamo l’accesso indicizzato?

 public class IndexedGlobalTable extends GlobalTable { public List getKeysAsList() { return Collections.unmodifiableList(new ArrayList(keySet())); } public Key getKeyAt(int index) { return getKeysAsList().get(index); } public Value getValueAt(int index) { return get(getKeyAt(index)); } } 

Che ne dici di chiavi ordinate?

 public class SortedGlobalTable extends GlobalTable { @Override public Iterator  iterator() { return Collections .unmodifiableSortedSet(new TreeSet(keySet())).iterator(); } } 

Ogni volta che hai bisogno dell’una o dell’altra visione dei dati, basta istanziare la sottoclass appropriata.

Naturalmente, se i dati globali sono davvero una buona idea in primo luogo è un’altra domanda, ma almeno Monostate ti dà più flessibilità nel modo in cui la usi.

monostare e singleton sono due facce della stessa medaglia (stato globale):

  • monostare forza un comportamento (solo un valore lungo tutte le istanze di class)
  • singleton forza un vincolo strutturale (solo una istanza)

l’uso di singleton non è trasparente

vale a dire:

 Singleton singleton = Singleton.getInstance(); 

l’utilizzo della monostazione è trasparente

vale a dire:

 MonoState m1 = new MonoState(); MonoState m2 = new MonoState(); // same state of m1 

Ecco cosa ha da dire Robert C. Martin : Singleton vs. Monostate (pdf)

SINGLETON viene utilizzato al meglio quando si dispone di una class esistente che si desidera vincolare tramite la derivazione e non è necessario che tutti debbano chiamare il metodo instance () per ottenere l’accesso. La monostazione viene utilizzata al meglio quando si desidera che la natura singolare della class sia trasparente per gli utenti o quando si desidera utilizzare derivati ​​polimorfici del singolo object.

Qualcuno dovrebbe solo notare che singoletti e monostati sono schemi estremamente pericolosi. Tendono a essere abusati da codificatori pigri che non vogliono pensare alla vita dell’object che vogliono fare in un singleton. Rendono i test più difficili e creano sistemi inflessibili strettamente vincolati.

È estremamente raro trovare una situazione in cui un singoletto o un monostatico siano realmente necessari. Il metodo preferito per la collaborazione tra gli oggetti è Dipendenza Iniezione.

È stato scritto molto su questo:

  • accu singleton anti-pattern article
  • scot densmore su singltons è il male
  • accumulare sovraccarico di singleton

La differenza tra i due modelli è uno tra comportamento e struttura. Il modello SINGLETON rafforza la struttura della singolarità. Impedisce la creazione di più di una istanza. Considerando che MONOSTATO rafforza il comportamento della singolarità senza imporre vincoli strutturali.

Vantaggi del SINGLETON

  • Applicabile a qualsiasi class. È ansible modificare qualsiasi class in un SINGLETON semplicemente rendendo privati ​​i suoi costruttori e aggiungendo le funzioni statiche e la variabile appropriate.
  • Può essere creato attraverso la derivazione. Data una class, puoi creare una sottoclass che è un SINGLETON.
  • Valutazione pigra. Se SINGLETON non viene mai utilizzato, non verrà mai creato.

Costi del SINGLETON

  • La distruzione non è definita. Non esiste un buon modo per distruggere o disabilitare un SINGLETON. Se si aggiunge un metodo di rimozione delle autorizzazioni che annulla l’istanza, altri moduli nel sistema potrebbero contenere ancora un riferimento all’istanza SINGLETON. Le chiamate successive all’istanza causeranno la creazione di un’altra istanza, causando l’esistenza di due istanze concorrenti.

  • Non ereditato. Una class derivata da un SINGLETON non è un singleton. Se deve essere un SINGLETON, è necessario aggiungervi la funzione statica e la variabile.

  • Efficienza. Ogni chiamata all’istanza richiama l’istruzione if. Per la maggior parte di quelle chiamate, l’istruzione if è inutile.

  • Non trasparente. Gli utenti di un SINGLETON sanno che stanno utilizzando un SINGLETON perché devono richiamare il metodo Instance.

Vantaggi del MONOSTATO

  • Trasparenza. Gli utenti di un MONOSTATO non si comportano diversamente dagli utenti di un object normale. Gli utenti non hanno bisogno di sapere che l’object è MONOSTATO.

  • Derivabilità. I derivati ​​di un MONOSTATO sono MONOSTATI. In effetti, tutti i derivati ​​di un MONOSTATO fanno parte dello stesso MONOSTATO. Tutti condividono le stesse variabili statiche.

  • Polimorfismo. Poiché i metodi di un MONOSTATO non sono statici, possono essere sovrascritti in una derivata. Così diversi derivati ​​possono offrire un comportamento diverso rispetto allo stesso insieme di variabili statiche.

  • Creazione e distruzione ben definite. Le variabili di un MONOSTATO, essendo statiche, hanno tempi di creazione e distruzione ben definiti.

Costi di MONOSTATO

  • Nessuna conversione Una class normale non può essere convertita in una class MONOSTATE tramite derivazione.

  • Efficienza. Un MONOSTATO può passare attraverso molte creazioni e distruzioni perché è un object reale. Queste operazioni sono spesso costose.

  • Presenza. Le variabili di un MONOSTATO occupano spazio, anche se il MONOSTATO non viene mai utilizzato.

Sviluppo software agile, principi, modelli e pratiche Robert C. Martin