Design Patterns
239 pág.

Design Patterns


DisciplinaEngenharia de Software I4.631 materiais51.715 seguidores
Pré-visualização50 páginas
it to map 
 instances.put(key, instance);
 }
 
 return instance;
 }
 }
 // other fields and methods ...
Multiton pattern 51
 }
To avoid this (expensive) synchronization for many reader-threads in a highly concurrent environment one may also
combine the multiton pattern with double-checked locking:
This code is wrong, it could result in concurrent get() and put() which is not allowed for a HashMap.
 public class FooMultiton {
 private static final Map<Object, FooMultiton> instances = new HashMap<Object, FooMultiton>();
 
 private FooMultiton() /* also acceptable: protected, {default} 
*/ {
 /* no explicit implementation */
 }
 
 public static FooMultiton getInstance(Object key) {
 // Our &quot;per key&quot; singleton
 FooMultiton instance = instances.get(key);
 
 // if the instance has never been created ...
 if (instance == null) {
 synchronized (instances) {
 
 // Check again, after having acquired the lock to 
make sure 
 // the instance was not created meanwhile by 
another thread
 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 ...
 }
Multiton pattern 52
Action Script 3.0/ Flex
 import flash.utils.Dictionary;
 
 public class InternalModelLocator {
 private static var instances:Dictionary = new Dictionary();
 
 public function InternalModelLocator() {
 /* Only one instance created with 
GetInstanceMethod*/
 }
 
 
 /* module_uuid can be a String -------- 
 In case of PureMVC &quot;multitonKey&quot; (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);
 }
Multiton pattern 53
 return instance;
 }
 }
 }
}
C++
Implementation from StackOverflow [1]
#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 pattern 54
 Multiton(const Multiton&) {}
 Multiton& operator= (const Multiton&) { return *this; }
 static std::map<Key, T*> instances;
};
template <typename Key, typename T>
std::map<Key, T*> Multiton<Key, T>::instances;
#endif
// example usage
class Foo : public Multiton<Foo> {};
Foo& foo1 = Foo::getRef(&quot;foobar&quot;);
Foo* foo2 = Foo::getPtr(&quot;foobar&quot;);
Foo::destroy();
PHP
<?php
//orochi
// 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 &quot;Hello $string\n&quot;;
 }
}
class GoodBye extends Multiton {
 public function __construct($string = 'my', $string2 = 'darling')
 {
Multiton pattern 55
 echo &quot;Goodbye $string $string2\n&quot;;
 }
}
$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(&quot;MyClass0&quot;)
b=MyClass(&quot;MyClass0&quot;)
Multiton pattern 56
c=MyClass(&quot;MyClass1&quot;)
print a is b #True
print a is c #False
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,