Quali altri pattern posso usare per questo singleton?

4

Ho un po 'di codice che usa un plugin e un core model, che ruota intorno a quattro oggetti principali: Core , Server , Logger e Parser , in ordine leggermente particolare.

Il Core funge da factory centrale, con un catch: è associato a un singolo contesto di rendering (molto di questo è legato alla grafica, ma gli altri dettagli non sono importanti). Gli oggetti che crea e gestisce sono specifici per quel core e possono essere creati più core con diversi contesti. I core non possono mai condividere risorse tra loro. Core è inizializzato da un file di configurazione; più su questo più tardi. Il Core deve avere, dalla sua creazione, un Server , Parser e Logger .

Il Server gestisce il caricamento e l'inizializzazione di tutti i plugin, nonché la creazione di oggetti da essi. Funziona come un singolo server di plugin in-process e registro oggetti, simile in molti modi a un server COM in-process STA. Poiché i plug-in vengono caricati nel processo, non un particolare Core , sono abbastanza sicuro che sia appropriato. Server deve avere Parser e Logger .

Il Logger gestisce i messaggi di registrazione, in particolare gli errori, sul disco. Fa una scrittura di file preformattata molto semplice, con alcuni filtri di base "log level". Il Logger richiede un Parser per la risoluzione dei percorsi dei file.

Il Parser gestisce la sostituzione delle variabili, in particolare nei percorsi. Ad esempio, un plugin può richiedere il file $(root)/resources/a.txt e Parser lo sostituirà con la directory radice dell'applicazione; o $(startup)/a.txt per la directory di avvio. Roba semplice Le variabili sono contenute in Parser stesso e molte sono specifiche del thread. Tuttavia, alcuni sono legati a un singolo Core e quindi immettono nel ...

File di configurazione. Ogni Core viene inizializzato da un file di configurazione, che contiene una moltitudine di impostazioni: plugin per Server , variabili per Parser e un file per Logger . Ogni Core può utilizzare un file di configurazione diverso e molto probabilmente lo sarà.

Nel mio modello attuale, Server , Logger e Parser sono singleton. Tutti devono fornire un'unica istanza globale, accessibile dal nucleo e dai plug-in (e l'altro), potenzialmente prima che sia stato creato un Core . Tutte gestiscono le funzioni a livello di processo, ma Logger e Parser gestiscono alcune funzionalità Core -level.

Il problema con questo è che, per rendere Logger e / o Parser Core -specifici, il Server avrebbe quindi bisogno delle proprie istanze, che sarebbero potenzialmente prive di caratteristiche importanti (come quale file usare per Logger ). Server gestisce anche il lavoro molto chiaramente comune a tutto il processo: non c'è modo di caricare un plug-in in un singolo Core , non è così che funzionano le librerie condivise.

In una versione precedente, avevo creato tutti e quattro questi quando è stato creato un Core e appartengono a uno Core specifico. Ciò ha tuttavia causato alcuni problemi e stranezze: il Core carica se stesso come un "plug-in" all'avvio, ma il Server ha avuto la stessa durata del Core , rendendo questo strano. Il Parser ha un numero di variabili che appartengono al processo: la directory iniziale, la directory root e così via. Il Logger deve precedere il Core in qualche modo, in particolare la fase di caricamento dei plug-in, in modo che gli errori possano essere registrati con precisione.

Le mie domande sono:

  • Questa configurazione è troppo sovradimensionata? La separazione delle responsabilità tra gli oggetti sembra buona, ma forse troppo divisa.
  • Quale modello / i di design, sia esso singleton o altro, è / sono appropriato in questo caso, per questi oggetti?
posta ssube 16.02.2012 - 20:04
fonte

1 risposta

3

Ecco i miei punti:

  1. C'è una differenza tra avere solo un'istanza dell'oggetto nell'intera applicazione contro un oggetto che diventa singleton in modo che chiunque chiama new() trovi magicamente theInstance .

  2. Nel tuo caso, non c'è alcun vantaggio che il server sia singleton perché nessuno crea server diverso da main() . È semplicemente semplice averlo come oggetto ordinario. Anche se è singleton, verrà chiamato solo una volta!

  3. Parser dovrebbe mai essere singleton o per un motivo diverso qui. Se ho capito bene, l'unico ruolo di parser è quando viene lanciato core ; Idealmente dovrebbe seguire use-and-throw pattern piuttosto che singleton

  4. Anche parser continua a servire alcune query specifiche fino a core lo vuole, in base a parser dovrebbe essere un'istanza per core perché la stessa istanza di parser non dovrebbe mai condividere informazioni su vari differenti core s. Rende parser dedicato per core .

  5. La maggior parte delle persone progetta logger come un singleton. Non è davvero un grosso problema, tuttavia, se sei un sistema multi-thread un singleton logger è un grande cattivo. Prima di tutto, ogni singleton deve essere protetto da thread. Supponiamo che, anche se rendi il thread sicuro, ogni volta che un thread x chiama il logger è occupato a fare printf per thread y quindi un risultato thread x attende mentre idealmente dovresti preoccuparti di ottenere il massimo dal tuo quad -Core sistema e servire quante più richieste possibili.

  6. Idealmente, l'unico caso reale in cui logger dovrebbe essere centralizzato o singleton è dove l'ordine esatto degli eventi deve essere registrato uno per uno. Per la maggior parte dei casi, diversi file e messaggi con i loro timestamp di solito sono migliori anche per il debug.

Quindi per me Server (che è un'istanza) è creato da main() e core , parser e logger sono una tupla nata e muore per richiesta (sempre insieme). Ogni tupla non conosce lo stato o l'esistenza di altre tuple del genere, e ciò è buono in modo che il numero arbitrario di thread possa essere istanziato in parallelo (un thread per tupla) senza perdere la scalabilità ma preservando l'accoppiamento lento.

L'unica cosa è - significa che non stai usando nessun modello di design! Ma non è una brutta cosa. È non necessario che l'inclusione di un motivo di progettazione renda il design necessariamente migliore.

Ricorda:

There are really rare reasons where using singleton becomes must; everywhere else, using singleton is always an invitation to problems.

    
risposta data 16.02.2012 - 22:45
fonte

Leggi altre domande sui tag