$theTitle=wp_title(" - ", false); if($theTitle != "") { ?>
Talks around Computer Science and Stuff
In: Singleton
13 Mar 2010So, 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).
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.