In my last blog I covered the singleton design pattern (DP), showing how and when to use it. In this article I am going to cover a very similar design pattern called the multiton.
A multiton is almost exactly the same as a singleton, the one slight difference is a multiton can store multiple instances of itself. Contrary to a singleton, which can only store one instance of itself.
When to use a multiton
The ideal use for a multiton is when you need to create multiple instances of a particular class and you want to store references to each instance. This is most useful when you’re only creating a small amount of the class in question and you want to access different instances in different parts of your code. I’m going to use a database example again, solely because it’s the best real world use case. If you start creating more than 5-10 instance of a multiton, than you probably shouldn’t be using a multiton and rather storing the objects in a dependency injection container (DIC). Multitons are only for creating a small collection of objects.
Rules when creating a multiton
- Just like a singleton, multitons should have a private __construct() method. Instances should be created using a static getInstance() method.
- Each instance of the multiton which is created should be stored inside a static $instances attribute
- When the getInstance() method is called a value should be passed as the only argument, this value should be used as the key when storing the instance inside the $instances attribute.
- To retrieve an existing instance, the name of the instance you want to retrieve should be passed to the getInstance() method, which will return the pre-initialised instance, instead of creating a new instance.
Drawbacks
For full details on the drawback you should check out the article I wrote on singletons, as they have the same problems. But here is a quick summary.
- Multitons add dependencies to your code because the are called globally.
- They are hard to test because of their use of static methods and attributes.
Code Example
class Database { /** * Used to store and provide instances for the getInstance() method */ private static $instances = array(); /** * Hidden constructor, only callable from within this class */ private function __construct() { } /** * Create a new instance if one doesn't exist with the key provided. * Once an instance has been created, or if it was already created, return it. * @param $key the key which the instance should be stored/retrieved * @return self */ public static function getInstance($key) { // Check if an instance exists with this key already if(!array_key_exists($key, self::$instances)) { // instance doesn't exist yet, so create it self::$instances[$key] = new self(); } // Return the correct instance of this class return self::$instances[$key]; } /** * Hidden magic clone method, make sure no instances of this class * can be cloned using the clone keyword */ private function __clone() { } } // Create first instance to the master database $master = Database::getInstance('master'); var_dump($master); // object(Database)#1 (0) { } // Create second instance of this class for a logger database $logger = Database::getInstance('logger'); var_dump($logger); // object(Database)#2 (0) { } // Retrieve the existing 'master' instance from the multiton // this would normally be done in script, which doesn't have the instance already $masterDupe = Database::getInstance('master'); var_dump($masterDupe); // object(Database)#1 (0) { } // Database objects cannot be initialise with the new keyword, doing so will cause fatal errors // Fatal error: Call to private Database::__construct() from invalid context $dbFatalError = new Database(); // Database objects cannot be cloned, doing so will cause a fatal error // PHP Fatal error: Call to private Database::__clone() $dbCloneError = clone $masterDupe;17 Love This
Pingback: My Homepage
Is it possible to write a simple cache module using multitons and how
Sure, are you looking for a PHP solution? You can use a popular dependency injection container like Pimple or the Symfony DependencyInjection component.