1

I have an external thermometer connected via USB that is controlled by my SW. Different parts of my system will use it but never at the same time (all in one thread). However, it is a single device communicating over an established connection so for some reason I think either its method (GetTemperature) should be static or I could do it as Singleton. I will be happy for suggestions. Thanks

2
  • Singleton has so many problems, some mentioned below. It also does not guarantee uniqueness: you could write another identical copy, serialisation is usually a way to get another. Also A static class is an implementation of singleton (using the strict definition of pattern), this implementation is often called mono-state. Jul 28, 2014 at 13:20
  • Yep, I remember the system I was working on that had 1 external thermometer. No brainer, it became a singleton. However, I also remember them adding the requirement that we also want an internal temperature sensor. Funny how often 1 turns into more.
    – Dunk
    Jul 28, 2014 at 13:59

4 Answers 4

6

No, it's not a good candidate.

  1. What if you buy a second thermometer in order to get the temperature in two different locations?

  2. What if you want to create a mock or a stub of your thermometer in order to unit test parts which rely on it?

With singleton, you'll end up doing something like:

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();

This code:

  • Cannot be tested, since it relies on the thermometer which cannot be replaced by a mock or a stub,

  • Is difficult to maintain or reuse given its dependency on the actual thermometer.

If, on the other hand, you use instances and Dependency Injection:

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);

you remove the dependencies, making it possible to use general classes RealTimeDisplay and Chart which can then be reused for anything else, like measuring the CPU load or the number of WTFs per second during a coding review. With:

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

they can easily be tested as well.

Can't you use both dependency injection and singleton? You can, but the point of using a singleton is to being able to use the instance anywhere without having to pass it through parameters down the chain. In my example, you only instantiate thermometer once, making a singleton useless.

The fact that the singleton guarantees you that only one instance will ever be created is not particularly useful in my example. RealTimeDisplay and Chart already receive an instance of a thermometer, so the incentive to create another thermometer is low. The only remaining risk is to end up with code like this in the entry point of the application:

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

but it's unlikely that a maintainer will do such change.

12
  • From the nature of the device, there will never be another thermometer. In addition, the connection should remain open and hence the class needs to be at least static. Also mind you that the class we talk about contains just three methods (GetTemperature, Start and Stop - these can be mocked).
    – user144171
    Jul 28, 2014 at 11:17
  • At least the fact that you may have to mock the thermometer for the tests makes it a bad candidate for being a singleton. Jul 28, 2014 at 11:22
  • 1
    Right, but singleton would at least ensure that only one instance exists. I mean, if I limit the existence to just one instance and then pass it, isnt basically singleton?
    – user144171
    Jul 28, 2014 at 11:29
  • 1
    @Telastyn: a medical one. You only measure a single spot.
    – user144171
    Jul 28, 2014 at 11:52
  • 2
    @user144171 It does not matter that you only plan to have one thermometer, or that the connection should always be open. It would be bad design to make it a static class or a singleton. Limiting your application to a single instance using DI is a cleaner, more flexible design. "Singleton" as you are imagining it (with a getInstance method) is practically an antipattern these days. Jul 28, 2014 at 11:57
1

You can inject a singleton just fine. Don't understand why people are saying don't use it. A singleton is just something guaranteed to have one and only one instance. Using a singleton doesn't rule out injection.

In Java the recommended way to implement is to use an Enum. Again very injectable.

Have it implement a common interface so that more thermometers can be added/or replaced at a latter date/easily mocked.

public enum Thermometer implements IThermometer{
    DEFAUlT;

    public BigDecimal getTemperature(){
        return null;
    }
}

and then just use constructor injection (or your DI framework of choice) :

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

Injecting like this, using an interface, means you can easily change the code at a later date to use something that it is not a singleton, or is a the old fashioned getInstance() singleton.

3
  • You can mix DI and Singleton, but what's the point? The benefit of a rightly used Singleton is to make it possible to use it anywhere without passing the instance through the parameters. Jul 28, 2014 at 12:45
  • @MainMa thats not its only point. If its singleton it makes it clear there is only ever one of them to any developer, and of course my enum example guarantees on a jvm level that there is only one instance - which is the point of a singleton. But you can still easily inject a mock, refactor later. Jul 28, 2014 at 12:56
  • 3
    I have never seen a case where singleton improves a design, but many times where it makes it worse. (well one exception: if code is written with the assumption that there will be one instance, then fix it or wrap in singleton.The fact that it is a singleton should flag that it is a candidate for fixing.) Singleton violates single responsibility: A singleton implements the main responsibility, plus a factory/builder. Therefore use a factory/builder pattern to create an/the instance of the class. Jul 28, 2014 at 13:27
0

From a maintainability and code reuse stand point I'd say no, however that assumes a lifetime to the project.

While you could use a Singleton here, adding more thermometers would become messy and difficult. Using RAII is definitely the way to go, and Singleton does that, but I'd still make the thermometer instance a non-global object.

If the code will live longer than the immediate task, it would be more useful to build a class which encapsulates all of the thermometer communication, as you would with a singleton, but then wrap/store that inside of a singleton. This is a little more complicated, but makes it much easier to reuse the code later and expand into having more thermometers.

0

So I just bought this USB hub with seven ports. And I had this great idea to put a thermometer into each room of my home. The problem is... there's a singleton object!

The other problem is that other people don't have a thermometer at all. In that case a singleton is one object too many.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.