È un candidato per Singleton?

1

Ho un termometro esterno collegato via USB che è controllato dal mio SW. Diverse parti del mio sistema lo useranno ma mai contemporaneamente (tutto in un thread). Tuttavia, è un singolo dispositivo che comunica su una connessione stabilita, quindi per qualche ragione penso che il suo metodo (GetTemperature) dovrebbe essere statico o potrei farlo come Singleton. Sarò felice per i suggerimenti. Grazie

    
posta user144171 28.07.2014 - 13:05
fonte

4 risposte

6

No, non è un buon candidato.

  1. Che cosa succede se acquisti un secondo termometro per ottenere la temperatura in due posizioni diverse?

  2. Che cosa succede se si desidera creare un finto o uno stub del termometro per unire le parti di test che si basano su di esso?

Con singleton, finirai per fare qualcosa del tipo:

public class TemperatureRealTimeDisplay
{
    // Show the current temperature to the user.
    public void Show()
    {
        var temperature = Thermometer.Instance.Measure();
        ...
    }
}

public class TemperatureChart
{
    // Record the temperature in order to display a chart over time.
    public void OnTimer()
    {
        var temperature = Thermometer.Instance.Measure();
        ...
    }
}

...

var display = new TemperatureRealTimeDisplay();
var chart = new TemperatureChart();

Questo codice:

  • Non può essere testato, poiché si basa sul termometro che non può essere sostituito da un mock o da uno stub,

  • È difficile da mantenere o riutilizzare data la sua dipendenza dal termometro attuale.

Se, d'altra parte, si utilizzano le istanze e Iniezione di dipendenza:

public interface IProbe<TResult>
{
    public TResult Measure();
}

public class HardwareThermometer : IProbe<Temperature>
{
    ...
}

public class RealTimeDisplay<TMetric>
{
    public RealTimeDisplay<TMetric>(IProbe<TMetric> probe)
    {
        this.probe = probe;
    }

    public void Show()
    {
        var current = this.probe.Measure();
        ...
    }
}

public class Chart<TMetric>
{
    public Chart<TMetric>(IProbe<TMetric> probe)
    {
        this.probe = probe;
    }

    public void OnTimer()
    {
        var current = this.probe.Measure();
        ...
    }
}

...

var thermometer = new HardwareThermometer();
var temperatureDisplay = new RealTimeDisplay(thermometer);
var temperatureChart = new Chart(thermometer);

rimuovi le dipendenze, rendendo possibile utilizzare le classi generali RealTimeDisplay e Chart che possono essere riutilizzate per qualsiasi altra cosa, come la misurazione del carico della CPU o il numero di WTF al secondo durante una revisione del codice . Con:

public class ProbeStub : IProbe<int>
{
    ...
}

possono essere facilmente testati.

Non puoi usare sia dependency injection che singleton? È possibile, ma il punto di utilizzo di un singleton consiste nell'essere in grado di utilizzare l'istanza ovunque senza doverla passare attraverso i parametri lungo la catena. Nel mio esempio, crei solo un'istanza di thermometer una sola volta, rendendo inutile un singleton.

Il fatto che il singleton garantisca che solo una istanza verrà mai creata non è particolarmente utile nel mio esempio. RealTimeDisplay e Chart ricevono già un'istanza di un termometro, quindi l'incentivo a creare un altro termometro è basso. L'unico rischio rimanente è di finire con un codice come questo nel punto di accesso dell'applicazione:

var temperatureDisplay = new RealTimeDisplay(new HardwareThermometer());
var temperatureChart = new Chart(new HardwareThermometer());

ma è improbabile che un manutentore esegua tali modifiche.

    
risposta data 28.07.2014 - 13:15
fonte
1

È possibile iniettare un singleton bene. Non capisco perché la gente sta dicendo di non usarlo. Un singleton è solo qualcosa garantito per avere una e una sola istanza. L'uso di un singleton non esclude l'iniezione.

In Java il modo migliore per implementare è usare un Enum. Di nuovo molto iniettabile.

Ha implementato un'interfaccia comune in modo che più termometri possano essere aggiunti / o sostituiti in una data successiva / facilmente derisi.

public enum Thermometer implements IThermometer{
    DEFAUlT;

    public BigDecimal getTemperature(){
        return null;
    }
}

e quindi basta usare il constructor injection (o il framework DI scelto):

public class MyService{
  public MyService(IThermometer thermometer){
    this.thermometer - thermometer;}
  }
  // do some stuff that uses thermometer.getTemperature();
}

Iniettare in questo modo, usando un'interfaccia, significa che puoi facilmente cambiare il codice in un secondo momento per usare qualcosa che non è un singleton, o è un vecchio singleton getInstance ().

    
risposta data 28.07.2014 - 14:17
fonte
0

Dal punto di vista della manutenibilità e del riutilizzo del codice, direi di no, tuttavia questo presuppone una vita intera per il progetto.

Mentre potresti usare un Singleton qui, aggiungere più termometri diventerebbe disordinato e difficile. Usare RAII è sicuramente la strada da percorrere, e Singleton lo fa, ma farei comunque che l'istanza del termometro non sia oggetto globale.

Se il codice vivrà più a lungo del compito immediato, sarebbe più utile costruire una classe che incapsuli tutte le comunicazioni del termometro, come faresti con un singleton, ma poi avvolgere / archiviare quello all'interno di un singleton. Questo è un po 'più complicato, ma rende molto più facile riutilizzare il codice in un secondo momento ed espandersi per avere più termometri.

    
risposta data 15.09.2015 - 17:31
fonte
0

Quindi ho appena acquistato questo hub USB con sette porte. E ho avuto questa grande idea di mettere un termometro in ogni stanza della mia casa. Il problema è ... c'è un oggetto singleton!

L'altro problema è che le altre persone non hanno affatto un termometro. In tal caso un singleton è un oggetto di troppo.

    
risposta data 15.09.2015 - 22:06
fonte

Leggi altre domande sui tag