2012-05-02 9 views
9

Mi rendo conto che c'è molta discussione sui singleton e sul perché sono cattivi. Non è di questa domanda. Comprendo gli svantaggi dei singleton.Voglio un'alternativa di design a un singleton

Ho uno scenario in cui l'utilizzo di un singleton è semplice e sembra avere senso. Tuttavia, voglio un'alternativa che realizzerà ciò di cui ho bisogno senza un sovraccarico.

La nostra applicazione è progettata come un client che in genere viene eseguito su laptop sul campo e comunica con un server back-end. Abbiamo una barra di stato nella parte inferiore dell'applicazione principale. Contiene alcune aree di testo che mostrano varie statue e informazioni oltre a diverse icone. Le icone cambiano la loro immagine per indicare il loro stato. Come un'icona GPS che indica se è collegata o meno così come lo stato di errore.

La nostra classe principale si chiama MobileMain. Possiede l'area della barra di stato ed è responsabile della sua creazione. Abbiamo quindi una classe StatusBarManager. StatusBarManager è attualmente una classe statica, ma potrebbe anche essere un singleton. Ecco l'inizio della lezione.

public static class StatusBarManager 
{ 
    static ScreenStatusBar StatusBar; 

    /// <summary> 
    /// Creates the status bar that it manages and returns it. 
    /// </summary> 
    public static ScreenStatusBar CreateStatusBar() 
    { 
     StatusBar = new ScreenStatusBar(); 
     return StatusBar; 
    } 

Il MobileMain richiede StatusBarManager per StatusBar. Quindi utilizza StatusBar. Nessun'altra classe vede StatusBar, solo StatusBarManager.

Gli aggiornamenti alla barra di stato possono provenire praticamente da qualsiasi punto dell'applicazione. Ci sono circa 20 classi che possono aggiornare le aree di testo sulla barra di stato e classi aggiuntive che aggiornano gli stati delle icone.

Ci saranno solo uno StatusBar e un StatusBarManager.

Qualche suggerimento per una migliore implementazione?

Alcuni pensieri che ho avuto:

Fai lo StatusBarManager una classe di istanza. Nella mia classe MobileMain mantieni un'istanza pubblica statica della classe StatusBarManager. Quindi, per eseguire gli aggiornamenti della barra di stato, chiamare MobileMain.StatusBarManager.SetInformationText o qualche altro metodo del gestore. StatusBarManager non sarebbe un singleton, ma MobileMain creerebbe solo un'istanza statica di esso. Il problema qui è che MobileMain ora ha StatusBar e StatusBarManager, che gestisce solo lo StatusBar di sua proprietà. È inoltre disponibile un'istanza statica disponibile a livello globale per StatusBarManager, solo un proprietario diverso.

Un'altra idea era usare qualcosa come una classe EventEggregator. Non ne ho mai usato uno, ma ho letto su di loro. Immagino che il concetto sia che sarebbe una classe globalmente disponibile. In ogni classe che desidera aggiornare la barra di stato pubblicherà un evento StatusBarUpdate. StatusBarManager sarebbe l'unica classe che si iscrive all'evento StatusBarUpdate e riceverà tutte le notifiche. Ho letto però che può finire con perdite con questo approccio se non si presta attenzione a cancellarsi dagli eventi durante la pulizia degli oggetti. Questo approccio vale la pena esaminare?

+1

Questo post contiene un numero di domande. Scegli uno alla volta per ottenere una risposta. – mydogisbox

+0

hai pensato di usare MEF o Unity? Qui si registra una singola istanza di tutto ciò che si desidera con un contenitore in modo da poterlo recuperare da qualche altra parte. – stijn

+0

Una buona lettura, relativa alla denominazione di StatusBarManager; http://www.codinghorror.com/blog/2006/03/i-shall-call-it-somethingmanager.html – Patrick

risposta

2

Avere una classe StatusBar o una classe StatusBarManager o meno non è un grosso problema. Ma avere molte classi nella tua app a conoscenza di StatusBars e StatusBarManagers è una cattiva idea, causerà un forte accoppiamento, e un giorno probabilmente il dolore.

Come?

Immaginate che i componenti che attualmente segnalano lo stato di una barra di stato debbano essere riutilizzati in un'altra app che - utilizza una console di testo per riportare lo stato? - segnala lo stato a più posti? o - non segnala lo stato!

Migliore alternativa: -Evento di ascolto. Esporre un evento Status Changed sulla tua classe (puoi usare una callback), o forse su una risorsa condivisa esistente che le tue classi hanno in comune. Altre parti, come la barra di stato, possono iscriversi all'evento. E dovrebbe annullare l'iscrizione ogni volta che l'abbonamento non è più necessario/valido, per evitare perdite, come si menziona!

-Da che hai taggato WPF, per WPF, avere una proprietà di dipendenza 'StatusText', potrebbe sembrare un'altra opzione allettante, con questo approccio quando hai più proprietà di stato, hai bisogno di un modo per capire quale è ti dice lo stato più interessante che deve essere visualizzato sulla tua barra di stato ora! Che potrebbe essere un gestore di eventi modificato, multibinding (blech, complex) o dependency modificato.

Tuttavia, ti consigliamo di mantenere DependencyObjects e DependencyProperties limitati al tuo livello UI il più possibile. Il motivo è che si basano implicitamente su un Dispatcher sul thread dell'interfaccia utente e pertanto non possono essere adattati facilmente per le attività non relative all'interfaccia utente.

Poiché ci sono molte diverse parti della vostra applicazione si può anche trovare forse è ragionevole avere una combinazione di entrambi questi, utilizzando alcuni un posto e chi un'altra.

+1

Grazie per la risposta. Volevo chiarire la mia comprensione del tuo approccio migliore. Dovremmo inserire un evento StatusChanged in ogni classe che aggiorna la barra di stato. Il rilancio di quell'evento che avrà la barra di stato che lo sottoscrive. È questo che stai suggerendo? In tal caso, StatusBar o StatusBarManager devono essere a conoscenza di ogni classe che lo aggiorna per poter sottoscrivere l'evento StatusChanged. Capisco il problema del fatto che tutte le nostre classi conoscono StatusBarManager per la riusabilità, il che è in parte il motivo per cui voglio apportare la modifica. – WPFNewbie

+0

Ho anche considerato l'utilizzo di un NotificationManager, che potrebbe rientrare nel tuo suggerimento di una risorsa condivisa. Potrebbe gestire tutte le notifiche, inclusa la barra di stato. Quello che sarebbe l'ideale è avere un'interfaccia, quindi le classi potrebbero essere riutilizzate in qualsiasi progetto purché avessero una classe che ha implementato l'interfaccia di INotifier, ma non penso che si possa farlo con una classe singleton o statica. – WPFNewbie

+0

Ah - c'è un buon punto: StatusBar in realtà non ha bisogno di sapere su ogni classe! Puoi invece avere un metodo StatusBar.UpdateStatus(), e poi in una classe di livello superiore (che ha comunque conoscenza di tutto per altri motivi), fai un po 'di binding per fare in modo che tutti i gestori di eventi chiamino quel metodo. –

3

Preferisco le classi statiche che contengono i tuoi oggetti. Quindi la quantità di oggetti a cui puoi accedere viene ricondotta dall'interfaccia offerta dalla classe statica. Statico non è male finché l'applicazione continua a ridimensionare.

Un'altra buona alternativa ai singleton è il pattern Monostate, in cui si dispone di una classe che implementa campi statici privati ​​per rappresentare il comportamento "singleton".

Vedi:
Monostate
Monostate vs. Singleton

UPDATE: E spesso mi aiuta a mantenere un REST come api in mente, anche per le strutture interne del programma. Avere una classe che viene aggiornata da tutte le parti e inviare notifiche a tutti è difficile da controllare rispetto alle condizioni di aumento e infinito loop (Aggiorna -> Evento -> Aggiorna -> ...)

Build a (statico o no) Interfaccia della barra di stato a cui è possibile accedere dove ne hai bisogno. Attraverso una classe statica in cui si ottiene l'accesso all'interfaccia della barra di stato o all'iniezione di dipendenza se si utilizzano tali tecniche (non consigliato per progetti di dimensioni minori). Ogni chiamata all'interfaccia della barra di stato deve essere indipendente da qualsiasi evento che potrebbe essere generato dalla barra di stato per evitare ulteriori problemi con condizioni di aumento. Pensa all'interfaccia della barra di stato come un sito web che può essere chiamato da altre parti del programma per spingere e tirare le informazioni.

+0

Quindi, per ricapitolare, non si vede nulla di sbagliato con il nostro attuale progettista in cui StatusBarManager è una classe statica? Ho guardato attraverso gli altri link che hai incluso. Per quanto riguarda la monostazione, il problema è che non voglio che sia trasparente. Tutti dovrebbero sapere che c'è solo una barra di stato ed è quello che stanno aggiornando. Questo è il mio sentimento su di esso comunque. Il mio problema principale con le classi statiche e singltons è la riusabilità delle classi che fanno riferimento a loro. Ora hai un riferimento a una classe globale che dovrebbe essere soddisfatta se hai riutilizzato la classe in un altro progetto. – WPFNewbie

+0

Di solito la "cosa cattiva" sulla statica è. Quando si hanno molte classi dipendono da alcune classi statiche che rendono impossibile il refactoring e il testing. Se la barra di stato non è la stat, ma l'interfaccia della barra di stato è statica, la barra di stato può ancora essere scambiata per i casi di test. La classe statica sarà abbastanza piccola da riscriverla secondo necessità. – Tarion

+0

Se si vuole eliminare la classe statica, vedo solo la possibilità di Iniezione di Dipendenza (Proprietà o Iniezione del Costruttore). Iniezione costruttore richiede lo StatusBar (o StatusBarHandler) in ogni costruttore che potrebbe essere troppo. PropertyInjection si baserà sul fatto che si inietta la proprietà. Questo di solito è fatto da un MicroKernel. L'intero programma si baserà su quel kernel. DI è un buon modo se hai bisogno di un codice verificabile ma puoi confondervi in ​​progetti più piccoli perché è più difficile eseguire il debug. – Tarion

-1

È difficile dare consigli senza conoscere più l'architettura della tua applicazione, ma forse dovresti prendere in considerazione l'iniezione di dipendenza. Ad esempio, passare un'istanza StatusBar al costruttore di ogni classe che la utilizza direttamente.

+0

Sembra un'idea approssimativa. Ora devi passare parametri extra in tutti i tuoi oggetti al momento della costruzione, aggiungere un codice extra nei costruttori per inizializzarli, campi aggiuntivi in ​​oggetti dappertutto per memorizzare molti riferimenti a ciò che è in realtà un singolo oggetto e tutti i tuoi tipi non può più essere compilato senza il tipo StatusBar. –

1

È possibile utilizzare semplicemente lo schema Observer e aggiungere lo StatusBar come listener ai 20 oggetti. Questo eliminerà i singleton e seguirà meglio SRP e DIP, ma dovrai valutare se vale la pena. Un singleton può essere migliore se l'indirezione aggiunge troppa complessità e l'iniezione di dipendenza non è possibile.

public class StatusBar implements StatusListener { 
} 

public interface StatusListener { 
    public statusChanged(String newStatus) 
} 
0

Le lezioni dipenderanno implicitamente su qualsiasi Singleton uso ed esplicitamente a qualsiasi parametro nel costruttore. Suggerirei di aggiungere un'interfaccia al singleton, quindi solo i metodi necessari saranno esposti alle classi usando IStatusBar. Questo è più codice, ma faciliterà il test dell'unità.

Problemi correlati