Multiton pattern: Difference between revisions

Content deleted Content added
Undid revision 595478260 by 78.137.50.206 (talk)
Bender the Bot (talk | contribs)
m Drawbacks: HTTP to HTTPS for Blogspot
 
(41 intermediate revisions by 33 users not shown)
Line 1:
{{Short description|Software engineering design pattern}}
[[Image:Multiton.svg|thumb|right|UML diagram of the multiton]]
{{Plain image with caption|Image:Multiton.svg|UML diagram of the multiton}}
In [[software engineering]], the '''multiton pattern''' is a [[design pattern (computer science)|design pattern]] similar to the [[singleton pattern|singleton]], which allows only one instance of a class to be created. The multiton pattern expands on the singleton concept to manage a [[associative array|map]] of named instances as key-value pairs.
In [[software engineering]], the '''multiton pattern''' is a [[design pattern (computer science)|design pattern]] which generalizes the [[singleton pattern]]. Whereas the [[singleton pattern | singleton]] allows only one instance of a class to be created, the multiton pattern allows for the controlled creation of multiple instances, which it manages through the use of a [[associative array|map]].
 
Rather than having a single instance ''per application'' (e.g. the {{Javadoc:SE|package=java.lang|java/lang|Runtime}} object in the [[Java (programming language)|Java programming language]]) the multiton pattern instead ensures a single instance ''per key''.
 
The multiton pattern does not explicitly appear as a pattern in the highly regarded [[object-oriented programming]] textbook ''[[Design Patterns]]''.<ref>{{cite book |last1=O'Docherty |first1=Mike |title=Object-oriented analysis and design: understanding system development with UML 2.0 |date=2005 |publisher=Wiley |___location=Chichester |isbn=0470092408 |page=341}}</ref> However, the book describes using a '''registry of singletons''' to allow subclassing of singletons,<ref>{{cite book |title=Design patterns: elements of reusable object-oriented software |date=2011 |publisher=Addison-Wesley |___location=Boston, Mass. Munich |isbn=0-201-63361-2 |page=130}}</ref> which is essentially the multiton pattern.{{Citation needed|date=April 2012}}
Most people and textbooks consider this a singleton pattern{{Citation needed|date=April 2012}}. For example, multiton does not explicitly appear in the highly regarded [[object-oriented programming]] text book ''[[Design Patterns (book)|Design Patterns]]'' (it appears as a more flexible approach named '''registry of singletons''').
 
==ExamplesDescription==
While it may appear that the multiton is a [[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 [[wikt:null|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 (data structure)|tree structure]].
Here are simplified example implementations in several languages.
 
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 (computer science)|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.
===Java===
 
==Drawbacks==
<source lang=Java>
This pattern, like the [[Singleton pattern]], makes [[unit testing]] far more difficult,<ref>{{Cite web | url=https://googletesting.blogspot.com/2008/11/clean-code-talks-global-state-and.html |title = Clean Code Talks - Global State and Singletons}}</ref> as it introduces [[global variables|global state]] into an application.
public class FooMultiton {
private static final Map<Object, FooMultiton> instances = new HashMap<Object, FooMultiton>();
 
With garbage collected languages it may become a source of memory leaks as it introduces global strong references to the objects.
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 ...
}
</source>
 
==Implementations==
In Java, the multiton pattern can be implemented using an [[enumerated type]], with the values of the type corresponding to the instances. In the case of an enumerated type with a single value, this gives the singleton pattern.
 
In C#, we can also use enums, as the following example shows:
if (instance == null) {
allowCreation = true;
instance = new InternalModelLocator();
allowCreation = false;
instances[module_uuid] = instance;
}
return instance;
}
}
</source>
 
<syntaxhighlight lang="c#" line="1">
===C#===
using System;
<source lang=CSharp>
using System.Collections.Generic;
using System.Collections.Concurrent;
 
public enum MultitonType
namespace MyApplication
{
Zero,
class FooMultiton
{One,
Two
private static readonly ConcurrentDictionary<object, FooMultiton> _instances
= new ConcurrentDictionary<object, FooMultiton>();
 
private FooMultiton() {}
 
public static FooMultiton GetInstance(object key)
{
return _instances.GetOrAdd(key, (k) => new FooMultiton());
}
}
}
</source>
 
public class Multiton
===C++===
{
Adjusted implementation from [http://stackoverflow.com/questions/2346091/c-templated-class-implementation-of-the-multiton-pattern StackOverflow]
private static readonly Dictionary<MultitonType, Multiton> instances =
new Dictionary<MultitonType, Multiton>();
 
private MultitonType type;
<source lang=Cpp>
#ifndef MULTITON_H
#define MULTITON_H
 
private Multiton(MultitonType type)
#include <map>
#include <string>
 
template <typename T, typename Key = std::string>
class Multiton
{
public:
static void destroy()
{
this.type = type;
for (typename std::map<Key, T*>::const_iterator it = instances.begin(); it != instances.end(); ++it)
delete (*it).second;
instances.clear();
}
 
public static T*Multiton getPtrGetInstance(constMultitonType Key& keytype) {
{
typename std::map<Key, T*>::const_iterator it = instances.find(key);
// Lazy init (not thread safe as written)
// Recommend using Double Check Locking if needing thread safety
if (!instances.TryGetValue(type, out var instance))
{
instance = new Multiton(type);
 
if (it != instances.endAdd(type, instance)) {;
return (T*)(it->second);
}
 
T* instance = new T();
instances[key] = instance;
return instance;
}
 
public override string ToString()
static T& getRef(const Key& key) {
{
return *getPtr(key);
return $"My type is {this.type}";
}
 
// Sample usage
protected:
public static void Main(string[] args)
Multiton() {}
~Multiton() {}
Multiton m0 = Multiton.GetInstance(MultitonType.Zero);
 
Multiton m1 = Multiton.GetInstance(MultitonType.One);
private:
Multiton(const m2 = Multiton&.GetInstance(MultitonType.Two) {};
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();
</source>
 
Console.WriteLine(m0);
===PHP===
Console.WriteLine(m1);
<source lang=PHP>
Console.WriteLine(m2);
<?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];
}
}
</syntaxhighlight>
 
==References==
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
</source>
 
===Python===
<source lang=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')
 
</source>
 
====Using decorators====
<source lang=Python>
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
</source>
 
===Perl===
<source lang="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
</source>
 
== 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 (data structure)|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,<ref>http://googletesting.blogspot.com/2008/11/clean-code-talks-global-state-and.html</ref> as it introduces [[global variables|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.
 
== References ==
{{Reflist}}
 
==External links==
* [httphttps://raa.ruby-langrubygems.org/projectgems/multiton/versions/0.0.1 Multiton implementation in Ruby language]
* [httphttps://tracgithub.puremvc.orgcom/PureMVC_AS3_MultiCorePureMVC/browserpuremvc-as3-multicore-framework/tagsblob/1.0.4master/src/org/puremvc/as3/multicore/patterns/facade/Facade.as Multiton usage in PureMVC Framework for ActionScript 3]
* [http://gen5.info/q/2008/07/25/the-multiton-design-pattern/ Article with a C# Multiton implementation, example of use, and discussion of memory issues]
 
{{Design Patterns patterns}}
<!--Categories-->
 
[[Category:Software design patterns]]
[[Category:Articles with example Java code]]