2011-12-22 11 views

risposta

19

Creare un enum con un'istanza

enum Singleton { 
    INSTANCE; 

    private Field field = VALUE; 
    public Value method(Arg arg) { /* some code */ } 
} 

// You can use 
Value v = Singleton.INSTANCE.method(arg); 

EDIT: Il Java Enum Tutorial mostra come aggiungere campi e metodi per un enum.


BTW: Spesso, quando è possibile utilizzare un Singleton, non si ha realmente bisogno di uno come classe di utilità farà la stessa cosa. La versione ancora più corta è solo

enum Utility {; 
    private static Field field = VALUE; 
    public static Value method(Arg arg) { /* some code */ } 
} 

// You can use 
Value v = Utility.method(arg); 

Dove Singletons è utile quando implementano un'interfaccia. Ciò è particolarmente utile per i test quando si utilizza l'iniezione di dipendenza. (Uno dei punti deboli dell'uso di una sostituzione Singleton o della classe di utilità nei test unitari)

ad es.

interface TimeService { 
    public long currentTimeMS(); 
} 

// used when running the program in production. 
enum VanillaTimeService implements TimeService { 
    INSTANCE; 
    public long currentTimeMS() { return System.currentTimeMS(); } 
} 

// used in testing. 
class FixedTimeService implements TimeService { 
    private long currentTimeMS = 0; 
    public void currentTimeMS(long currentTimeMS) { this.currentTimeMS = currentTimeMS; } 
    public long currentTimeMS() { return currentTimeMS; } 
} 

Come si può vedere, se il codice utilizza TimeService ovunque, è possibile iniettare sia la VanillaTimeService.INSTANCE o un new FixedTimeService() in cui è possibile controllare il tempo dall'esterno cioè i francobolli volta sarà lo stesso ogni volta che si esegue il test.

In breve, se non è necessario il singleton per implementare un'interfaccia, tutto ciò che serve è una classe di utilità.

+0

@Pater Grazie per la rapida risposta –

+0

Non capisco ... non puoi chiamare nessun metodo sul tuo singleton –

+0

@remi bourgarel un java enum è solo una classe. Basta aggiungere le variabili, i metodi e un costruttore all'enum Singleton (dopo la dichiarazione di INSTANCE) come faresti con qualsiasi altra classe e INSTANCE li ha. – josefx

1

Seguire la ricetta enum Joshua Bloch in "Java efficace" 2a edizione. Questo è il modo migliore per creare un singleton.

Non capisco perché questo si presenta così tanto. Non è singleton un modello di progettazione screditato? Il GoF lo voterebbe fuori dall'isola oggi.

1

È possibile utilizzare uno dei contenitori IoC (ad esempio Google Guice) e utilizzare la classe come singleton (desiderosa o pigra - dipende dalle proprie esigenze). È semplice e flessibile poiché la creazione di istanze è controllata dal framework IoC: non è necessario alcun cambiamento di codice se, ad esempio, deciderai di rendere la tua classe non singleton più tardi.

+0

Nel contesto di un'interrogazione, non è una buona idea risolvere piccoli problemi come quello introducendo enormi framework come un contenitore IoC. –

+0

Perché? IoC è una cosa abbastanza ordinaria ora. Ed è un vantaggio se l'intervistato ne è a conoscenza e propone di utilizzare il framework IoC come una delle possibili soluzioni. – Artem

+0

Sì, l'IoC è comunemente noto al giorno d'oggi. Di gran lunga non è utilizzato in tutti e tutti i progetti. Quindi, a meno che l'intervistatore non abbia mostrato un interesse per qualsiasi framework IoC prima, assumerei che la domanda vuole mettere alla prova la conoscenza della lingua stessa. Se non mostri che sai come le cose semplici possono essere fatte in un modo semplice ma solo in un modo complicato che coinvolge diversi framework pesanti, allora si può presumere che la tua normale abilità di problem solving funzioni allo stesso modo.
La cosa migliore da fare: mostrare entrambe le soluzioni. –

8
public class Singleton { 
    public static final Singleton instance = new Singleton(); 
    private Singleton() {} 
    public void foo() {} 
} 

quindi utilizzare

Singleton.instance.foo(); 
+1

Per completezza: aggiungere un costruttore privato no-arg. –

+0

Ottimo! Grazie A.H.! (Il mio errore normale :) – andrey

0

Utilizzare una fabbrica di oggetto, prendere il vostro oggetto Singleton da questa fabbrica.

ObjectFactory factory; 
.... 
MySingletonObject obj = factory.getInstance(MySingletonObject.class); 

ovviamente, ci sono molti schemi per aiutarti a raggiungere questo obiettivo. la struttura della molla è una scelta popolare.

+0

Non fabbrica usando un metodo statico? Questo è qualcosa che non vuole. – Eduard

0

Dal costruttore è necessario verificare se esiste già un'istanza della classe. Quindi è necessario memorizzare il riferimento all'istanza singleton in variabile statica o classe. Quindi, nel contructor di singleton, verificherei sempre se esiste un'istanza di classe singleton. Se sì, non farei nulla se non lo creerei e impostassi il riferimento.

2

Un altro approccio è il singleton holder idiom che offre inizializzazione on demand:

public class Something { 
     private Something() { 
     } 

     private static class LazyHolder { 
       public static final Something INSTANCE = new Something(); 
     } 

     public Something getInstance() { 
       return LazyHolder.INSTANCE; 
     } 
} 

(esempio modificato, metodo getInstance fatto non statica)

noti che singletons standalone come questo dovrebbe essere evitato se possibile perché promuove stato globale, porta a un codice difficile da leggere e dipende da un singolo contesto del classloader per citare alcuni possibili inconvenienti.

Problemi correlati