Բազմակի օգտագործման նախագծման մոդելը նման է եզակի օգտագործման նախագծման մոդելին, որը թույլ է տալիս ստեղծել դասի միայն մեկ նմուշ։ Բազմակի օգտագործման մոդելն ընդլայնում է Եզակիի հնարավորությունները և թույլ է տալիս ունենալ անուններով հիշվող նմուշների մասիվ, ընդ որում, անունները հանդիսանում են նմուշների բանալի-արժեքները։
Մարդկանցից շատերը այն համարում են եզակի օգտագործման նախագծման մոդելի ձև։ Օրինակ բազմակի օգտագործման ձևանմուշը ԳօՖի գրքում միայն հանդես է գալիս որպես եզակի օգտագործման մոդելի մասնակի ձև, որը թույլ է տալիս ռեգիստրացնել եզակի օգտագործման մոդելները՝ այն ավելի ճկուն դարձնելու նպատակով։
Բազմակի օգտագործման նախագծման ձևանմուշը գլոբալ հասանելիություն է ապահովում միայն անուններով նմուշներ ունեցող դասի բոլոր նմուշներին։
Առաջին հայացքից թվում է, թե բազմակի օգտագործումը ոչ ավելի է քան հեշ աղյուսակների օգտագործումով հասանելիությունը սինխրոնիզացնող մոդել, բայց այն երկու կարևոր տարբերություն ունի։ Առաջին հերթին բազմակի օգտագործումը հայցողներին թույլ չի տալիս mapping-ներ ավելացնել։ Երկրորդ հերթին բազմակի օգտագործումը երբեք null
կամ դատարկ հղում չի վերադրաձնում։ Դրա փոխարեն այն ստեղծում և պահում է բազմակիի նմուշը նրա հետ կապված «բանալու» (անգլ.՝ key) հետ։ Նույն բանալիով հաջորդող կանչերի դեպքում կվերադարձվի իրական նմուշը։ Հեշ աղյուսակը միայն հանդիսանում է իրականացման դետալներից մեկը, բայց ոչ միակը։ Ձևանմուշը հեշտացնում է ծրագրային ապահովումից (անգլ.՝ application) ընդհանուր (անգլ.՝ shared) օբյեկտների դուրս բերումը։
Քանի որ ավազան օբյեկտը ստեղծվում է միայն մեկ անգամ՝ ասոցացված լինելով դասի (նմուշի փոխարեն), ապա բազմակի օգտագործումը պահում է իր հարթ վարքագիծը (անգլ.՝ behavior) և չի վերածվում ծառատիպ կառուցվածքի։
Բազմակի օգտագործման ձևանմուշը ունիկալ է նրանով, որ այն ապահովում է կենտրոնացված հասանելիություն մի ուղղությամբ (այսինքն բոլոր բանալիները գտնվում են միևնույն անվանատարածքում), որտեղ ամեն մի նմուշ ունի իր սեփական վիճակը։ Այսպիսով ձևանմուշը հանդիսանում է օյեկտները համակարգում ինդեքսավորումով պահող մոդել։ Բայց և այնպես, բազմակի օգտագործումը ունի սահմանափակ կիրառություն եզակի համակարգում՝ ի տարբերություն բազմաթիվ բաշխվածություն ունեցող համակարգերում (անգլ.՝ distributed systems)։
Այս ձևանմուշը եզակի օգտագործման ձևանմուշի նման թեսթավորումը դարձնում է բավականին դժվար[1], քանի որ այն գլոբալ վիճակ է մտցնում ծրագրային ապահովվածության մեջ։
Բազմակի օգտագործման ձևանմուշը օբյեկտների վրա օգտագործում է գլոբալ հզոր հղումներ, որը որոշ ծրագրավորման լեզուներում կարող է բերել հիշողության կորստի (անգլ.՝ memory leaks)։
Ահա պարզեցված օգտագործման օրինակներ մի շարք ծրագրավորման լեզուներով.
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 ...
}
import flash.utils.Dictionary;
public class InternalModelLocator {
private static var instances:Dictionary = new Dictionary();
private static var allowCreation:boolean = false;
public function InternalModelLocator() {
if(!allowCreation){
throw new Error("Only one instance allowed to be created, and only 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) {
allowCreation = true;
instance = new InternalModelLocator();
allowCreation = false;
instances[module_uuid] = instance;
}
return instance;
}
}
using System.Collections.Generic;
using System.Collections.Concurrent;
namespace MyApplication
{
public class Multiton<T> where T : new() // generic multition.
{
private static readonly ConcurrentDictionary<object, T> _instances = new ConcurrentDictionary<object, T>();
private Multiton() { }
public static T GetInstance(object key)
{
return _instances.GetOrAdd(key, (k) => new T());
}
}
}
Բազմակի օգտագործման ձևանմուշի բավականին պարզ օրինակ private կոնստրուկտորով և ստեղծված օբյեկներ ռեգիստրացնող մոդելով.
//IVSR: Multiton design pattern
namespace IVSR.DesignPatterns.Multiton
{
public class Multiton
{
//read-only dictionary to track multitons
private static IDictionary<int, Multiton> _Tracker = new Dictionary<int, Multiton> { };
private Multiton()
{
}
public static Multiton GetInstance(int key)
{
//value to return
Multiton item = null;
//lock collection to prevent changes during operation
lock (_Tracker)
{
//if value not found, create and add
if(!_Tracker.TryGetValue(key, out item))
{
item = new Multiton();
//calculate next key
int newIdent = _Tracker.Keys.Max() + 1;
//add item
_Tracker.Add(newIdent, item);
}
}
return item;
}
}
}
Ճշգրտված իրականացումը 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
// 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
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')
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
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
|