Can we fix Singletons testability tight coupling?

It is well known that Singletons are anti-patters for several reasons:

  1. tight coupling
  2. singletons are pathological liars
  3. no testability
  4. inheritance is not available
  5. you cannot program to interfaces, you program to implementations

But there is the code:

class ISingleton
{
protected:
    ISingleton() {}

public:
    virtual ISingleton& getInstance() = 0;
    virtual void doSomething() = 0;
    virtual ~ISingleton(){}
};

class SingletonA : public ISingleton
{
public:
    virtual SingletonA& getInstance() override
    {
        static SingletonA instance;
        return instance;
    }

    virtual void doSomething() override
    {

    }
};

class SingletonB : public ISingleton
{
public:
    virtual SingletonB& getInstance() override
    {
        static SingletonB instance;
        return instance;
    }

    virtual void doSomething() override
    {

    }
};

class DependsOnSingleton
{
private:
    ISingleton& m_singleton;

public:
    DependsOnSingleton(ISingleton& singleton)
        : m_singleton {singleton}
    {

    }

    void use()
    {
        m_singleton.doSomething();
    }
};

Do you see any of the problems in the code listed above? And it completely assures that a single instance can be created. You can see here direct dependency injection is used, it could also be used with DI containers too. I think people just misunderstand what Singleton is for. Do I miss something?

3

Do you see any of the problems in the code listed above? And it
completely assures that a single instance can be created.

No, it absolutely does not.

class SingletonC : public ISingleton
{
public:
    virtual SingletonC& getInstance() override
    {
        return *this;
    }

    virtual void doSomething() override
    {

    }
};

Now you can make as many instances as you want. The whole idea of getInstance doesn’t even remotely make sense when it’s a non-static method, since by definition, you must already have an instance in order to call it.

Also, your code is not testable, since the implementations of SingletonA and SingletonB can’t be tested due to their statically stored mutable state, and they cannot accept interfaces DI-style since they are not constructed.

Since the getInstance method is non-static, that means you need to instantiate your class first. So if you want to have a instance of B, you need to make a “new B()” first. I don’t see any values of this. If you do new A() getInstance() will return a instance of type A

If you want to use singletons without the problems that come with the patterns. Use injections (either at construction or using setter) like Spring does.

You have the benefits of the singleton with way less cons of it.

Trả lời

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *