come refactoring molti singletons

7

Ho un programma python di medie dimensioni (~ 5000 linee di codice), che ho accumulato nel tempo, senza alcun piano particolare mentre procedevo. L'architettura con cui ho finito è composta da 5-6 oggetti Singleton di grandi dimensioni, ognuno dei quali gestisce un determinato aspetto del mio programma, come le comunicazioni del database, un server Web, un client di raccolta dati e calcoli interni.

Ritengo che l'uso di numerosi singleton come questo non sfrutti realmente il vero vantaggio della programmazione OO, ovvero che ti consenta facilmente di creare numerosi oggetti correlati. I miei singleton sono anche abbastanza dipendenti l'uno dall'altro, e se sviluppassi molto il programma (diciamo ~ 50.000 righe), posso vedere il mio approccio diventare spaghetti code.

Quindi mi chiedo se c'è un modo migliore per strutturare il mio programma. Per esempio. i miei singleton dovrebbero essere in realtà moduli separati? Ma allora come potrei avvicinarmi agli attributi che sono molto ben organizzati nei miei oggetti singleton? Ci sono altre opzioni di architettura?

Non ho molta familiarità con i modelli di progettazione (il libro GOF è sulla mia lista delle cose da fare) quindi forse ci sono design e / o pattern architettonici che sarebbero migliori per il mio programma?

    
posta funklute 14.10.2015 - 09:51
fonte

2 risposte

22

I singleton sono considerati "malvagi" da molti, e mentre un modello singleton ha i suoi usi sono pochi e lontani tra loro ... Ho lavorato con diverse codebase di grandi dimensioni e sono praticamente riuscito sempre a spostarli dai singleton.

Il modo più semplice per eliminare i singleton è:

  1. Introduci un'interfaccia in cima al tuo singleton : questo ti consente di separare il contratto dall'implementazione e riduce l'accoppiamento che hai all'attuale implementazione
  2. Fornisci un setter sul tuo singleton in modo da poter impostare l'istanza singleton da un unittest : questo ti consente di "scambiare" l'istanza singleton in un unittest.
  3. Crea le unittests sulla classe che vuoi cambiare : usando una simulazione dell'interfaccia presentata in 1 e il setter introdotto in 2 puoi ora scrivere le unittests sulla classe.
  4. Inietti il singleton invece di farlo staticamente : nella classe che dipende dal singleton, hai un modo per iniettare quel singleton (tramite l'interfaccia creata in 1). È possibile utilizzare l'iniezione del costruttore, i setter basati sui metodi .... Qualunque cosa funzioni per voi. Questa è la prima volta che tocchi la classe che stai rifacendo! I test introdotti in 3 ti aiuteranno a refactoring senza rompere nulla

Puoi evitare il passaggio 2 se vuoi farlo all-in, ma questo approccio è il più puro, nel senso che eviti di cambiare le classi che non hanno test per verificare che non si rompa nulla. Personalmente, trovo che questo sia un po 'eccessivo, ma YMMV. La premessa di base è che ti sposti verso una classe che ha inserito le dipendenze invece di essere scaricata staticamente.

Inoltre, anche se hai usi legittimi per un singleton dovresti ANALIZZARLI. I single servono a garantire che esista solo una singola istanza di una determinata classe. Lo schema classico con una funzione statica accessibile a livello globale consente di ottenere questo risultato, ma sfortunatamente ci allontana dall'iniezione di quell'istanza a causa del codice di esempio errato che galleggia sul web. Ci sono un sacco di framework che possono gestire l'iniezione delle dipendenze per te e molti di loro avranno un modo per configurare un oggetto in modo che la stessa istanza venga riutilizzata in tutta l'applicazione, rendendolo effettivamente un singleton.

    
risposta data 14.10.2015 - 10:44
fonte
11

La paura dei singleton è molto esagerata. Se hai bisogno di affidabilità, esattamente uno dei tanti grandi costrutti, non c'è niente di sbagliato nell'averli. (Se desideri invece scrivere moduli statici e il linguaggio non ti consente, potrebbe essere un problema con la lingua, non con il tuo programma.)

Un argomento comune contro i singleton è che sono difficili da deridere per i test unitari. Ma ciò si applica solo se si codifica la propria classe nel codice. Il modello singleton si preoccupa veramente di assicurarsi che esista solo una istanza di una classe specifica . Nessuno ti impedisce di avere diverse implementazioni di un'interfaccia di servizio, ciascuna di cui è un singleton e di scambiarle / inserirle / caricarle dinamicamente come necessario per scopi aziendali e di test.

    
risposta data 14.10.2015 - 10:42
fonte

Leggi altre domande sui tag