Singleton senza alcun stato

6

Ho lavorato a un progetto e ho trovato una soluzione funzionante, ma ora ho alcune domande su come ho risolto alcuni problemi nel codice. Prima di tutto, non sono esperto in schemi di design, ma conosco il modello (anti-) dei singleton e di solito li evito. Ma quello che uso abbastanza spesso, sono metodi% helper / utility% co.

Quindi il progetto su cui ho lavorato si basa sull'SDK del plug-in Atlassian. Ho implementato servlet, ho accesso ad alcuni dati tramite i componenti di Atlassian, tutto abbastanza semplice. Quando si arriva al punto di rendering delle pagine, le piattaforme Atlassian utilizzano Apache Velocity. Così costruisco la mia mappa di contesto e accedo agli oggetti in Velocity, tutto va bene. Ad un certo punto, voglio generare URL per collegarmi ad altri servlet o pagine. Quindi, creo una classe con metodi di generazione url static . Purtroppo, non posso accedere a quei metodi in Velocity, perché non esiste alcuna istanza che possa passare al contesto Velocity (che definisce l'ambito). Ma Velocity mi consente di utilizzare metodi statici tramite istanze della classe. La classe risultante assomiglia a questo (codice java):

public class Urls {
    private static Urls Singleton = new Urls();

    public static Urls getInstance() {
        return Singleton;
    }

    private Urls() { }

    public static String getBaseUrl() { ... }

    public static String forUserProfile(ApplicationUser user) { ... }

    ...
}

Ora, nel mio normale codice java, posso usare il metodo statico:

String myUrl = Urls.forUserProfile(myUser);

Ma posso anche passare il mio singleton al contesto velocity ...

context.put("urls", Urls.getInstance());

... per usarlo nel mio modello Velocity:

<a href="$urls.forUserProfile($myUser)">User profile</a>

Ho usato questo 'pattern' o altri simili nel mio progetto. C'è un nome per qualcosa di simile? Presumo che questo è piuttosto raro, perché normalmente si potrebbe semplicemente accedere ai metodi statici. Pensi che ci siano dei grossi svantaggi che ho dimenticato? Qualche ragione per non usare in questo modo? Qualche modo migliore?

    
posta Lukas Körfer 19.01.2017 - 13:36
fonte

4 risposte

8

Un singleton è un tipo elaborato di stato globale.

Il tuo Urls non è utilmente un singleton, perché non ha stato. Potresti anche non istanziarlo nel codice normale.

public class Urls {
    public Urls() { }
    // static methods ...
}

context.put("urls", new Urls());
    
risposta data 19.01.2017 - 13:51
fonte
2

Singleton senza stato non ha senso, quindi non c'è bisogno di imporre l'esistenza di un'unica entità. E se qualcosa ha bisogno di istanza, usa l'istanza.

MA ci può essere stato in un singleton senz'altro apolide. Puoi avere più implementazioni e lo stato è l'implementazione che stai utilizzando. E quindi il requisito che l'intero sistema usi la stessa implementazione ha senso, quindi rendendolo una specie di singleton iniettabile (in java senza frame esterni è possibile utilizzare ServiceLoader e creare un'istanza basata sulle implementazioni disponibili in fase di runtime).

    
risposta data 19.01.2017 - 16:05
fonte
1

Nessuna cosa

Non esiste un singleton senza stato. Il puntatore allo stato della singola istanza è . Questo puntatore non solo identifica l'unica istanza, ma definisce anche il tipo dell'istanza e il suo VMT e / o la spedizione tabella, nel senso che determina anche il comportamento.

Penso che tu stia chiedendo di un singleton che restituisce un oggetto privo di variabili membro.

L'unico stato per cui è necessario un singleton per gestire ...

... è la variabile statica che contiene il riferimento a One And Only Thing. Qualsiasi altro stato non è endemico per il modello singleton.

Se non esiste uno stato dell'oggetto, perché avere un singleton?

Un singleton è anche un fabbrica di un uomo povero. Una chiamata a Instance deve sempre restituire lo stesso oggetto, sì, ma potrebbe trattarsi di un oggetto di qualsiasi tipo che eredita dalla classe singleton stessa. Quindi potresti voler mantenere il modello singleton ai fini del polimorfismo. Ad esempio, potresti avere un DatabaseContext.Current di singleton che potrebbe restituire un OracleContext o SqlServerContext a seconda della configurazione.

Non dimenticare la compatibilità diretta

Anche se al momento il tuo singleton non ha variabili membro, potresti volerle aggiungere in seguito. Saranno facili da aggiungere. Se si elimina il modello, sarebbe più difficile ripristinarlo in un secondo momento quando si presentasse la necessità di quelle variabili membro.

Riguardo a YAGNI-- Finché il modello singleton si concentra concettualmente sul tuo dominio del problema, e non impone molto lavoro aggiuntivo, potrebbe comunque essere una decisione di progettazione giustificata, nonostante YAGNI.

Utilizza DI invece

Tutti odiano singoletti in questi giorni. L'approccio più moderno consiste nell'utilizzare l'iniezione di dipendenza con istanze per processo. Con DI è molto più facile creare l'isolamento necessario per i test automatici delle unità.

    
risposta data 19.01.2017 - 19:57
fonte
1

Uno degli aspetti più sfortunati del modello di Singleton è che è ampiamente comprensibile rispetto a quanto descritto nel libro Pattern di GoF. È davvero sottile, ma se guardi gli esempi di codice per quel modello, vedrai una classe Singleton astratta con molteplici implementazioni concrete. La maggior parte delle persone pensa che Singleton sia semplicemente un oggetto globale, ma non è proprio corretto.

Se lo ignori, allora, non ha senso avere un Singleton senza stato. Se tuttavia consideri il polimorfismo, può farlo. Ad esempio, diciamo di avere un'applicazione in cui è necessario essere in grado di configurare le regole globali per il modo in cui sono implementati determinati calcoli contabili, ad esempio l'arrotondamento. Quindi hai classe in questo modo:

public abstract class Accounting
{
   public static final Accounting getInstance()
   {
     //...
   }

   public abstract Money round(Money money);
}

Creerai quindi diverse versioni di questa classe di Contabilità e quindi implementerai una sorta di modo per configurare quale è stato usato in una determinata istanza dell'applicazione. Non è cruciale che questi oggetti contengano lo stato per essere utili. La possibilità di utilizzarli per sostituire le implementazioni dei metodi è sufficiente.

DI è più in voga per questo genere di cose e offre molta più flessibilità. Se questa flessibilità non è necessaria o crea effettivamente dei rischi, penso che valga la pena considerare un approccio polimorfico di Singleton. Non c'è nulla che ti impedisca di usare DI per configurare l'istanza Singleton in questo approccio.

In base all'esperienza passata, è probabile che qualcuno affermerà che non sto descrivendo il modello Singleton e che indicherò come prova alcune pagine web. Chiederei a chiunque con quella opinione di leggere effettivamente il modello inclusi gli esempi nel libro del GoF. La maggior parte dei siti web che spiegano questo modello stanno solo spiegando come implementare oggetti globali.

    
risposta data 19.01.2017 - 19:27
fonte

Leggi altre domande sui tag