Multiton pattern

In software engineering, the multiton pattern is a design pattern similar to the singleton, which allows only one instance of a class to be created. The multiton pattern expands on the singleton concept to manage a map of named instances as key-value pairs.
Rather than have a single instance per application (e.g. the java.lang.Runtime
object in the Java programming language) the multiton pattern instead ensures a single instance per key.
Most people and textbooks consider this a singleton pattern[citation needed]. For example, multiton does not explicitly appear in the highly regarded object-oriented programming text book Design Patterns (it appears as a more flexible approach named registry of singletons).
Examples
Here are simplified example implementations in several languages.
Java
public class FooMultiton {
private static final Map<Object, FooMultiton> instances = new HashMap<Object, FooMultiton>();
private FooMultiton() {
// no explicit implementation
}
public static synchronized FooMultiton getInstance(Object key) {
// Our "per key" singleton
FooMultiton instance = instances.get(key);
if (instance == null) {
// Lazily create instance
instance = new FooMultiton();
// Add it to map
instances.put(key, instance);
}
return instance;
}
// other fields and methods ...
}
Action Script 3.0/ Flex
import flash.utils.Dictionary;
public class InternalModelLocator {
private static var instances:Dictionary = new Dictionary();
private function InternalModelLocator() {
/* Only one instance created with GetInstanceMethod*/
}
/* module_uuid can be a String --------
In case of PureMVC "multitonKey" (this.multitonKey) can be used as unique key for multiple modules
*/
public static function getInstance(module_uuid:String):InternalModelLocator {
var instance:InternalModelLocator = instances[module_uuid];
if (instance == null) {
instance = new InternalModelLocator();
instances[module_uuid] = instance;
}
return instance;
}
}
C#
using System.Collections.Generic;
namespace MyApplication {
class FooMultiton {
private static readonly Dictionary<object, FooMultiton> _instances = new Dictionary<object, FooMultiton>();
private FooMultiton() {
}
public static FooMultiton GetInstance(object key) {
lock (_instances) {
FooMultiton instance;
if (!_instances.TryGetValue(key, out instance)) {
instance = new FooMultiton();
_instances.Add(key, instance);
}
return instance;
}
}
}
}
C++
Implementation from StackOverflow
#ifndef MULTITON_H
#define MULTITON_H
#include <map>
#include <string>
template <typename T, typename Key = std::string>
class Multiton
{
public:
static void destroy()
{
for (typename std::map<Key, T*>::const_iterator it = instances.begin(); it != instances.end(); ++it)
delete (*it).second;
instances.clear();
}
static T* getPtr(const Key& key) {
typename std::map<Key, T*>::const_iterator it = instances.find(key);
if (it != instances.end()) {
return (T*)(it->second);
}
T* instance = new T();
instances[key] = instance;
return instance;
}
static T& getRef(const Key& key) {
return *getPtr(key);
}
protected:
Multiton() {}
~Multiton() {}
private:
Multiton(const Multiton&) {}
Multiton& operator= (const Multiton&) { return *this; }
static std::map<Key, T*> instances;
};
template <typename T, typename Key>
std::map<Key, T*> Multiton<T, Key>::instances;
#endif
// example usage
class Foo : public Multiton<Foo> {};
Foo& foo1 = Foo::getRef("foobar");
Foo* foo2 = Foo::getPtr("foobar");
Foo::destroy();
PHP
<?php
// This example requires PHP 5.3+
abstract class Multiton {
private static $instances = array();
public static function getInstance() {
// For non-complex construction arguments, you can just use the $arg as the key
$key = get_called_class() . serialize(func_get_args());
if (!isset(self::$instances[$key])) {
// You can do this without the reflection class if you want to hard code the class constructor arguments
$rc = new ReflectionClass(get_called_class());
self::$instances[$key] = $rc->newInstanceArgs(func_get_args());
}
return self::$instances[$key];
}
}
class Hello extends Multiton {
public function __construct($string = 'World') {
echo "Hello $string\n";
}
}
class GoodBye extends Multiton {
public function __construct($string = 'my', $string2 = 'darling') {
echo "Goodbye $string $string2\n";
}
}
$a = Hello::getInstance('World');
$b = Hello::getInstance('bob');
// $a !== $b
$c = Hello::getInstance('World');
// $a === $c
$d = GoodBye::getInstance();
$e = GoodBye::getInstance();
// $d === $e
$f = GoodBye::getInstance('your');
// $d !== $f
Python
class A(object):
def __init__(self, *args, **kw):
pass
multiton = {}
a0 = multiton.setdefault('a0', A()) # get object by key, or create new and return it
a1 = multiton.setdefault('a1', A())
print multiton.get('a0')
print multiton.get('a1')
Using decorators
def multiton(cls):
instances = {}
def getinstance(name):
if name not in instances:
instances[name] = cls()
return instances[name]
return getinstance
@multiton
class MyClass:
...
a=MyClass("MyClass0")
b=MyClass("MyClass0")
c=MyClass("MyClass1")
print a is b #True
print a is c #False
Perl
use strict;
use warnings;
package MyClass {
use Moose;
has name => ( is => 'ro', isa => 'Str', required => 1 );
}
package Multiton { # version 5.14 package syntax
my %_objs;
our $_class = 'MyClass';
sub set {
my $self = shift;
my ( $key, @args ) = @_;
die "key unspecifiied" unless defined $key;
die "key is not a plain scalar" if ref($key);
if ( exists $_objs{$key} ) {
$_objs{$key};
} else {
$_objs{$key} = $_class->new(@args);
}
}
sub get {
my $self = shift;
my $class = ref($self) || $self;
$class->set(@_);
}
sub delete {
my $self = shift;
for my $key (@_) {
delete $_objs{$key};
}
}
}
my $a = Multiton->get( 'MyClassA' => ( name => 'Rover' ) );
my $b = Multiton->get( 'MyClassB' => ( name => 'Roger' ) );
my $c = Multiton->get('MyClassA');
print $a == $b ? 'true' : 'false', "\n"; # false
print $a == $c ? 'true' : 'false', "\n"; # true
Clarification of example code
While it may appear that the multiton is no more than a simple hash table with synchronized access there are two important distinctions. First, the multiton does not allow clients to add mappings. Secondly, the multiton never returns a null or empty reference; instead, it creates and stores a multiton instance on the first request with the associated key. Subsequent requests with the same key return the original instance. A hash table is merely an implementation detail and not the only possible approach. The pattern simplifies retrieval of shared objects in an application.
Since the object pool is created only once, being a member associated with the class (instead of the instance), the multiton retains its flat behavior rather than evolving into a tree structure.
The multiton is unique in that it provides centralized access to a single directory (i.e. all keys are in the same namespace, per se) of multitons, where each multiton instance in the pool may exist having its own state. In this manner, the pattern advocates indexed storage of essential objects for the system (such as would be provided by an LDAP system, for example). However, a multiton is limited to wide use by a single system rather than a myriad of distributed systems.
Drawbacks
This pattern, like the Singleton pattern, makes unit testing far more difficult,[1] as it introduces global state into an application.
With garbage collected languages it may become a source of memory leaks as it introduces global strong references to the objects.