Skip to main content
deleted 123 characters in body
Source Link
Loki Astari
  • 96.6k
  • 5
  • 125
  • 338
class MySingInterface
{
    public:
       virtual ~MySingInterface() {}  // Never foget the virtual destructor of
                                      // a class with virtual functions.
       // Other interfaces
};
class MySingInterfaceFactoryMySingFactory
{   
    public:
        virtual ~MySingInterfaceFactory() {}
        virtual MySingInterface& createMySingInterface() = 0;
};

class MySingInterfaceBuilderMySingBuilder
{
    static std::vector<MySingInterfaceFactory*>vector<MySingFactory*>   factories;             // This could be a map
                                                                // of factories or 
                                                                // anything else that
                                                                // makes sense to your
                                                                // project.


       static MySingInterface& buildInstance()
       {
             // decide what factory to use.
             // then call build (EG if you are in debug mode or unit test mode
             // you may want to build a different type of object from normal).
             //
             // I have shown an example where you can register multiple
             // factories but that may be overkill for you. Maybe you only need
             // to register one factory (which you decide in main and depends
             // on input arguments or config options or environment variables etc...)

             return factories[someIndex]->createMySingInterface();
       }
    public:
       MySingInterface&  getInstance()
       {
           static MySingInterface& instance = buildInstance();
           return instance;
       }

       static void addFactory(MySingInterfaceFactory&MySingFactory& factory)
       {
           factories.push_back(&factory);
       }
};

MySingInterfaceBuilderForUnitTestMySingFactoryForTest   mySingInterfaceBuilderForUnitTest;mySingFactoryForTest;
MySingInterfaceBuilderNormalCode   MySingFactoryForNormal mySingInterfaceBuilderForNormalCode;mySingFactoryForNormal;

int main()
{
    if (getenv("UNIT_TEST") != nullptr)
    {
        MySingInterfaceBuilderMySingBuilder::addFactory(mySingInterfaceBuilderForUnitTestmySingFactoryForTest);
    }
    else
    {
        MySingInterfaceBuilderMySingBuilder::addFactory(mySingInterfaceBuilderForNormalCodemySingFactoryForNormal);
    }

    MySingInterface& mSI = MySingInterfaceBuilder::getInstance();
}
class MySingInterface
{
    public:
       virtual ~MySingInterface() {}  // Never foget the virtual destructor of
                                      // a class with virtual functions.
       // Other interfaces
};
class MySingInterfaceFactory
{   
    public:
        virtual ~MySingInterfaceFactory() {}
        virtual MySingInterface& createMySingInterface() = 0;
};

class MySingInterfaceBuilder
{
    static std::vector<MySingInterfaceFactory*>   factories;    // This could be a map
                                                                // of factories or 
                                                                // anything else that
                                                                // makes sense to your
                                                                // project.


       static MySingInterface& buildInstance()
       {
             // decide what factory to use.
             // then call build (EG if you are in debug mode or unit test mode
             // you may want to build a different type of object from normal).
             //
             // I have shown an example where you can register multiple
             // factories but that may be overkill for you. Maybe you only need
             // to register one factory (which you decide in main and depends
             // on input arguments or config options or environment variables etc...)

             return factories[someIndex]->createMySingInterface();
       }
    public:
       MySingInterface&  getInstance()
       {
           static MySingInterface& instance = buildInstance();
           return instance;
       }

       static void addFactory(MySingInterfaceFactory& factory)
       {
           factories.push_back(&factory);
       }
};

MySingInterfaceBuilderForUnitTest   mySingInterfaceBuilderForUnitTest;
MySingInterfaceBuilderNormalCode    mySingInterfaceBuilderForNormalCode;

int main()
{
    if (getenv("UNIT_TEST") != nullptr)
    {
        MySingInterfaceBuilder::addFactory(mySingInterfaceBuilderForUnitTest);
    }
    else
    {
        MySingInterfaceBuilder::addFactory(mySingInterfaceBuilderForNormalCode);
    }

    MySingInterface& mSI = MySingInterfaceBuilder::getInstance();
}
class MySingInterface
{
    public:
       virtual ~MySingInterface() {}  // Never foget the virtual destructor of
                                      // a class with virtual functions.
       // Other interfaces
};
class MySingFactory
{   
    public:
        virtual ~MySingInterfaceFactory() {}
        virtual MySingInterface& createMySingInterface() = 0;
};

class MySingBuilder
{
    static std::vector<MySingFactory*>   factories;             // This could be a map
                                                                // of factories or 
                                                                // anything else that
                                                                // makes sense to your
                                                                // project.


       static MySingInterface& buildInstance()
       {
             // decide what factory to use.
             // then call build (EG if you are in debug mode or unit test mode
             // you may want to build a different type of object from normal).
             //
             // I have shown an example where you can register multiple
             // factories but that may be overkill for you. Maybe you only need
             // to register one factory (which you decide in main and depends
             // on input arguments or config options or environment variables etc...)

             return factories[someIndex]->createMySingInterface();
       }
    public:
       MySingInterface&  getInstance()
       {
           static MySingInterface& instance = buildInstance();
           return instance;
       }

       static void addFactory(MySingFactory& factory)
       {
           factories.push_back(&factory);
       }
};

MySingFactoryForTest   mySingFactoryForTest;
MySingFactoryForNormal mySingFactoryForNormal;

int main()
{
    if (getenv("UNIT_TEST") != nullptr)
    {
        MySingBuilder::addFactory(mySingFactoryForTest);
    }
    else
    {
        MySingBuilder::addFactory(mySingFactoryForNormal);
    }

    MySingInterface& mSI = MySingInterfaceBuilder::getInstance();
}
Source Link
Loki Astari
  • 96.6k
  • 5
  • 125
  • 338

Please never do this again:

    static ConcreteTrafficReturner* getInstance() {
      if (myself == 0)
      {
         myself = new ConcreteTrafficReturner();
      }

###Problem 1: You are not providing a concept of ownership. The user of your class has to actually read the code to understand that you are not only returning the pointer but ownership of the pointer.

###Problem 2: You are returning a pointer. So who decides when it should be deleted. What happens if the user of your class forgets to call delete!

A better way to implement this is:

    static ConcreteTrafficReturner& getInstance()
    {
       static ConcreteTrafficReturner    instance;    // created the first time
                                                      // get instance is called.
                                                      //
                                                      // automatically destroyed
                                                      // with other static storage
                                                      // duration objects.

        return instance;
    }

But really the above is a text book example (not a real world example) of a singelton. The singelton pattern is actually dangerous in that it binds your implementation to an object with mutable state. As such it should not be used in isolation it should be used in conjunction with a creator pattern (A factory is usually a good choice).

Note: Singelton is a design pattern. But in a lot of places it is also considered and anti-pattern so be very careful with its usage.

###Template problem Though technically correct. You may find problems with this design when using shared libraries. As each shared library may have its own instantiation of the templated object that is not shared. Thus you actually have multiple instances of your singelton.

###Summary: Personally I would not use a singelton (I think you can use other techniques). But if you have to use a singelton then it would look like this:

class MySingInterface
{
    public:
       virtual ~MySingInterface() {}  // Never foget the virtual destructor of
                                      // a class with virtual functions.
       // Other interfaces
};
class MySingInterfaceFactory
{   
    public:
        virtual ~MySingInterfaceFactory() {}
        virtual MySingInterface& createMySingInterface() = 0;
};

class MySingInterfaceBuilder
{
    static std::vector<MySingInterfaceFactory*>   factories;    // This could be a map
                                                                // of factories or 
                                                                // anything else that
                                                                // makes sense to your
                                                                // project.


       static MySingInterface& buildInstance()
       {
             // decide what factory to use.
             // then call build (EG if you are in debug mode or unit test mode
             // you may want to build a different type of object from normal).
             //
             // I have shown an example where you can register multiple
             // factories but that may be overkill for you. Maybe you only need
             // to register one factory (which you decide in main and depends
             // on input arguments or config options or environment variables etc...)

             return factories[someIndex]->createMySingInterface();
       }
    public:
       MySingInterface&  getInstance()
       {
           static MySingInterface& instance = buildInstance();
           return instance;
       }

       static void addFactory(MySingInterfaceFactory& factory)
       {
           factories.push_back(&factory);
       }
};

MySingInterfaceBuilderForUnitTest   mySingInterfaceBuilderForUnitTest;
MySingInterfaceBuilderNormalCode    mySingInterfaceBuilderForNormalCode;

int main()
{
    if (getenv("UNIT_TEST") != nullptr)
    {
        MySingInterfaceBuilder::addFactory(mySingInterfaceBuilderForUnitTest);
    }
    else
    {
        MySingInterfaceBuilder::addFactory(mySingInterfaceBuilderForNormalCode);
    }

    MySingInterface& mSI = MySingInterfaceBuilder::getInstance();
}