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.