Other problems with Singleton

In: Singleton

13 Mar 2010

So, again I will talk about Singleton and why you should be carefull with them. Everytime I think or discuss singleton the following things come in to my mind :

– Global State;
– Hard to test (refer to unit test post);
– Singletonite (I see Singletons everywhere);
– Violating the Single Responsibility Rule.

I could spent a few pages arguing and / or explaining those issues. Instead of that, I would recommend you to watch Miško Hevery’s presentations.

“Ok great,  I am  convinced. Singleton are bad. What are the alternatives ?”

Let’s suppose we have a class named article, that has a save() method allowing to persist this instance of an article (in a database or any kind of persistency layer).

/**
 * Singletons are my best friends
 */
class article
{
    public $title;
    public $text;

    public function save()
    {
        $storage = storage::getInstance();
        if(false === $storage->save())
        {
            logger::getInstance()->log("Sorry !");
        }
    }
}

$myArticle = new article();
$myArticle->title = 'I love sushi';
$myArticle->text = 'I really do...';
$myArticle->save();

What are the problems with the previous code ?

Well, first you can’t mock the storage object and therefore this class can be hard to unit test. Secondly, the save method has a dependency with two objects, those dependencies are hidden within the save method and as a consumer of this API, you would expect to be able to know what the collaborator and / or the dependencies of a class are without having to look at the implementation of some methods.

So, let’s get rid of all singletons !

/**
 * No Singleton, use collaborators instead
 */
class article
{
    protected $storage;
    protected $logger;

    public function __construct($storage, $logger)
    {
        $this->storage = $storage;
        $this->logger = $logger;
    }

    public function save()
    {
        if(false === $this->storage->save())
        {
            $this->logger->log("Sorry !");
        }
    }
}

// Having to instantiate "manually" the storage and logger
// is a actually a bit a pain
$storage = new storage($param1, $param2, ...);
$logger = new logger($paramA, $paramB, ...);

$myArticle = new article($storage, $logger);
$myArticle->title = 'I love sushi';
$myArticle->text = 'I really do...';
$myArticle->save();

We just need to pass the storage and logger objects into the constructor of the article object and now the article class is easier to test (easier to mock objects).


Be Sociable, Share!

Comment Form

Who am I?

My name is Bashar Al-Fallouji, I work as a Enterprise Solutions Architect at Amazon Web Services.

I am particularly interested in Cloud Computing, Web applications, Open Source Development, Software Engineering, Information Architecture, Unit Testing, XP/Agile development.

On this blog, you will find mostly technical articles and thoughts around PHP, OOP, OOD, Unit Testing, etc. I am also sharing a few open source tools and scripts.

  • Trinzia: Well done, my friend! [...]
  • vivek raj: Hello Bashar, It's really good that you wrote this code. but I'm confused some part. can you suppor [...]
  • irfan: I saw watch your youtube talk on clean and testable code. By the way very good talk. I was wondering [...]
  • Mohamed: Hello bashar, I hope you are doing well. Thank you for your hard work, and thank you for sharing [...]
  • alex davila: Hi Bashar is there any pick up example?? Regards Alex Davila [...]