The multiton pattern is a design pattern which generalizes the singleton pattern. Whereas the 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 map.

Task
Multiton
You are encouraged to solve this task according to the task description, using any language you may know.
Description


Task

Implement a basic Multiton class or other structure and test that it works as intended. If your language does not support the object oriented paradigm, then try to emulate a multiton as best you can with the tools available.

If your language supports multithreading, then you may optionally implement a thread safe variant as well.


Related task




Works with: C++ version 17
Translation of: Java
#include <iostream>
#include <unordered_map>
#include <mutex>
#include <memory>

enum class MultitonType {
    ZERO,
    ONE,
    TWO
};

class Multiton {
public:
    // Thread-safe method to get instance
    // Returns nullptr if the type is not found in the map
    static Multiton* getInstance(MultitonType type) {
        std::lock_guard<std::mutex> lock(mutex_);
        auto it = instances_.find(type);
        return (it != instances_.end()) ? it->second.get() : nullptr;
    }

    // Override toString equivalent
    std::string toString() const {
        std::string typeStr;
        switch (type_) {
            case MultitonType::ZERO: typeStr = "ZERO"; break;
            case MultitonType::ONE:  typeStr = "ONE";  break;
            case MultitonType::TWO:  typeStr = "TWO";  break;
        }
        return "This is Multiton " + typeStr;
    }

    // Overload << operator for easy printing
    friend std::ostream& operator<<(std::ostream& os, const Multiton& multiton) {
        os << multiton.toString();
        return os;
    }

private:
    // Private constructor to prevent direct instantiation
    explicit Multiton(MultitonType type) : type_(type) {}

    MultitonType type_;
    
    // Thread-safe static members
    static std::unordered_map<MultitonType, std::unique_ptr<Multiton>> instances_;
    static std::mutex mutex_;
    
    // Static initialization helper
    static bool initializeInstances();
    static bool initialized_;
};

// Static member definitions
std::unordered_map<MultitonType, std::unique_ptr<Multiton>> Multiton::instances_;
std::mutex Multiton::mutex_;
bool Multiton::initialized_ = Multiton::initializeInstances();

// Initialize all instances (equivalent to Java's static block)
bool Multiton::initializeInstances() {
    instances_[MultitonType::ZERO] = std::unique_ptr<Multiton>(new Multiton(MultitonType::ZERO));
    instances_[MultitonType::ONE]  = std::unique_ptr<Multiton>(new Multiton(MultitonType::ONE));
    instances_[MultitonType::TWO]  = std::unique_ptr<Multiton>(new Multiton(MultitonType::TWO));
    return true;
}

int main() {
    Multiton* alpha = Multiton::getInstance(MultitonType::ZERO);
    Multiton* beta  = Multiton::getInstance(MultitonType::ZERO);
    Multiton* gamma = Multiton::getInstance(MultitonType::ONE);
    Multiton* delta = Multiton::getInstance(MultitonType::TWO);

    std::cout << *alpha << std::endl;
    std::cout << *beta << std::endl;
    std::cout << *gamma << std::endl;
    std::cout << *delta << std::endl;

    // Verify that alpha and beta point to the same instance
    std::cout << "alpha == beta: " << (alpha == beta ? "true" : "false") << std::endl;

    return 0;
}
Output:
This is Multiton ZERO
This is Multiton ZERO
This is Multiton ONE
This is Multiton TWO
alpha == beta: true



Functional languages encourage the use of pure functions and immutable data structures, which naturally reduce the need for managing object lifecycles, F# is multiparadigm so lets try.

// Multiton. Nigel Galloway: April 1st., 2026
type Multitons= |N|I|G|E|L
module Multiton =
  let private n = Lazy.Create(fun() -> printfn "initializing";"N")
  let private i = Lazy.Create(fun() -> printfn "initializing";"I")
  let private g = Lazy.Create(fun() -> printfn "initializing";"G")
  let private e = Lazy.Create(fun() -> printfn "initializing";"E")
  let private l = Lazy.Create(fun() -> printfn "initializing";"L")
  let GetInstance=function N->n.Force|I->i.Force|G->g.Force|E->e.Force|L->l.Force

let n1=Multiton.GetInstance N
let n2=Multiton.GetInstance N
let g1=Multiton.GetInstance G
let g2=Multiton.GetInstance G
printfn "%s" (n1())
printfn "%s" (n2())
printfn "%s" (g1())
printfn "%s" (g2())
Output:
initializing
N
N
initializing
G
G
Translation of: Phix
Dim Shared As String permitido(2)
permitido(0) = "zero"
permitido(1) = "one"
permitido(2) = "two"
Dim Shared As Any Ptr instancias(2)

Type multiton
    id As String
    Declare Constructor(id As String)
End Type

Constructor multiton(id As String)
    Dim k As Integer = -1
    For i As Integer = 0 To Ubound(permitido)
        If permitido(i) = id Then
            k = i
            Exit For
        End If
    Next
    If k = -1 Then
        Print "not permitido"
        End 1
    End If
    If instancias(k) = 0 Then
        this.id = id & "_" & Str(Int(Rnd * 999))
        instancias(k) = @This
    Else
        This = *Cast(multiton Ptr, instancias(k))
    End If
End Constructor

Dim a As multiton = multiton("zero")
Dim b As multiton = multiton("one")
Dim c As multiton = multiton("two")
Dim d As multiton = multiton("zero")
' Dim e As multiton = multiton()        ' crashes
' Dim f As multiton = multiton("three") ' crashes
Dim e As multiton = multiton("one")
Dim f As multiton = multiton("two")

Print a.id
Print b.id
Print c.id
Print d.id
Print e.id
Print f.id

Sleep
Output:
zero_329
one_328
two_531
zero_329
one_328
two_531
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public final class MultitonTask {
	
    public static void main(String[] args) {
        Multiton alpha = Multiton.getInstance(MultitonType.ZERO);
        Multiton beta  = Multiton.getInstance(MultitonType.ZERO);
        Multiton gamma = Multiton.getInstance(MultitonType.ONE);
        Multiton delta = Multiton.getInstance(MultitonType.TWO);

        System.out.println(alpha);
        System.out.println(beta);
        System.out.println(gamma);
        System.out.println(delta);
    }
    
    private enum MultitonType { ZERO, ONE, TWO }

    private static final class Multiton {
    	   
    	// Thread safe method.
    	// Even if the enum 'MultitonType' is maliciously altered to include extra or different enum values,
    	// for example, 'THREE', the method will return null because the hash map does not contain the enum value.
        public static synchronized Multiton getInstance(MultitonType type) {        	
        	return instances.getOrDefault(type, null);
        }

        @Override
        public String toString() {
            return "This is Multiton " + type;
        }
        
        // Private constructor to prevent the class being instantiated
    	private Multiton(MultitonType aType) {
    	    type = aType;
    	}
    	
    	private MultitonType type;
    	
    	// Thread safe hash map
    	private static Map<MultitonType, Multiton> instances = new ConcurrentHashMap<MultitonType, Multiton>();
    	
    	// Create and pre-load into the map all available instances
    	static {
    		instances.put(MultitonType.ZERO, new Multiton(MultitonType.ZERO));
    		instances.put(MultitonType.ONE, new Multiton(MultitonType.ONE));
    		instances.put(MultitonType.TWO, new Multiton(MultitonType.TWO));
    	}
    	
    }
    
}
Output:
This is Multiton ZERO
This is Multiton ZERO
This is Multiton ONE
This is Multiton TWO

A registry (just in memory, not on disk) is used below instead of an enum. The registry is protected by a lock on the Multiton constructor, to prevent two threads creating the same object at the same time.

struct Multiton{T}
    data::T
    function Multiton(registry, refnum, data)
        lock(registry.spinlock)
        if 0 < refnum <= registry.max_instances && registry.instances[refnum] isa Nothing
            multiton = new{typeof(data)}(data)
            registry.instances[refnum] = multiton
            unlock(registry.spinlock)
            return multiton
        else
            unlock(registry.spinlock)
            error("Cannot create instance with instance reference number $refnum")
        end
    end
    function Multiton(registry, refnum)
        if 0 < refnum <= registry.max_instances && registry.instances[refnum] isa Multiton
            return registry.instances[refnum]
        else
            error("Cannot find a Multiton in registry with instance reference number $refnum")
        end
    end
end

struct Registry
        spinlock::Threads.SpinLock
        max_instances::Int
        instances::Vector{Union{Nothing, Multiton}}
        Registry(maxnum) = new(Threads.SpinLock(), maxnum, fill(nothing, maxnum))
end

reg = Registry(3)
m0 = Multiton(reg, 1, "zero")
m1 = Multiton(reg, 2, 1.0)
m2 = Multiton(reg, 3, [2])
m3 = Multiton(reg, 1)
m4 = Multiton(reg, 2)


for m in [m0, m1, m2, m3, m4]
   println("Multiton is $m")
end

# produce error
# m3 = Multiton(reg, 4, "three")

# produce error
m5 = Multiton(reg, 5)
Output:
Multiton is Multiton{String}("zero")
Multiton is Multiton{Float64}(1.0)
Multiton is Multiton{Vector{Int64}}([2])
Multiton is Multiton{String}("zero")
Multiton is Multiton{Float64}(1.0)  
ERROR: LoadError: Cannot find a Multiton in registry with instance reference number 5
# 20211215 Perl programming solution

use strict;
use warnings;

BEGIN {
   package MultitonDemo ;
   use Moo;
   with 'Role::Multiton';
   has [qw(attribute)] => ( is => 'rw');
   $INC{"MultitonDemo.pm"} = 1;
}

use MultitonDemo;

print "We create several instances and compare them to see if multiton is in effect.\n";
print "\n";
print "Instance   Constructor  Attribute\n";   
print "\n";
print "0            multiton       0\n";
print "1            multiton       1\n";
print "2            multiton       0\n";
print "3              new          0\n";
print "4              new          0\n";

my $inst0 = MultitonDemo->multiton (attribute => 0); 
my $inst1 = MultitonDemo->multiton (attribute => 1);
my $inst2 = MultitonDemo->multiton (attribute => 0); 
my $inst3 = MultitonDemo->new      (attribute => 0);
my $inst4 = MultitonDemo->new      (attribute => 0);

print "\n";
if ($inst0 eq $inst1) { print "Instance0 and Instance1 share the same object\n" };
if ($inst1 eq $inst2) { print "Instance1 and Instance2 share the same object\n" }; 
if ($inst0 eq $inst2) { print "Instance0 and Instance2 share the same object\n" }; 
if ($inst0 eq $inst3) { print "Instance0 and Instance3 share the same object\n" }; 
if ($inst3 eq $inst4) { print "Instance3 and Instance4 share the same object\n" };
Output:
We create several instances and compare them to see if multiton is in effect.

Instance   Constructor  Attribute

0            multiton       0
1            multiton       1
2            multiton       0
3              new          0
4              new          0

Instance0 and Instance2 share the same object
Library: Phix/Class

No attempt is made for thread safety, since multiple threads accessing these would need their own locking anyway, not that it is difficult to invoke enter_cs() and leave_cs().
I thought about adding a get_multiton() function to avoid calling new() all the time, but it would (probably/almost certainly) just invoke new() itself anyway.
Put this (up to "end class") in a separate file, to keep allowed and instances private. Classes are not [yet] supported under pwa/p2js.
Technically I suppose this should really use new_dict()/getd()/setd(), but I'm quite sure you'll cope somehow..

without javascript_semantics
sequence allowed = {"zero","one","two"},
         instances = {NULL,NULL,NULL}

public class Multiton
    public string id
    function Multiton(string id)
        integer k = find(id,allowed)
        if k=0 then crash("not allowed") end if
        if instances[k] = NULL then
            this.id = id&sprintf("_%d",rand(999))
            instances[k] = this
        end if
        return instances[k]
    end function
end class

Multiton a = new({"zero"}),
         b = new({"one"}),
         c = new({"two"}),
         d = new({"zero"}),
--       e = new(),         -- crashes
--       f = new({"three"}) -- crashes
         e = new({"one"}),
         f = new({"two"})

?a.id
?b.id
?c.id
?d.id
?e.id
?f.id
Output:
"zero_651"
"one_111"
"two_544"
"zero_651"
"one_111"
"two_544"
Library: Pluto-map

Although Pluto supports classes (in reality just fancy tables) and static methods, creating a multiton (or singleton) in the language is awkward because the 'private' modifier is ignored when applied to constructors or other static members. Any attempt to return anything other than the instance being created from the constructor is also ignored.

One way around these difficulties is to:

1. Store the instances map in a local variable and then place the multiton class in its own module so the instances map cannot be accessed directly.

2. Throw an error if someone attempts to create another instance of a pre-existing multiton for a given key by calling the constructor directly.

This approach is used in the following example.

The map keys can be any numbers or strings and cannot be changed by the user, though a method is provided to list the available keys. We use an ordered set to store them.

Thread safely is not normally a problem with Pluto as coroutines use cooperative rather than preemptive multithreading and so only one coroutine can run at a time.

-- Multiton.pluto --

require "map"

local mkeys = set.of(0, 1, 2)

local instances = {}

class multiton
    static function getInstance(key)
        if !instances[key] then new multiton(key) end
        return instances[key]
    end

    static function getKeys() return mkeys:keys():clone() end

    function __construct(private key)
        assert(mkeys:contains(key), "Argument is not a valid key.")
        assert(!instances[key], $"The multiton instance for key {key} already exists.")
        instances[key] = self
    end

    function print()
        print($"Hello, I'm a multiton for key {self.key}.")
    end
end
-- Multiton_user.pluto --

require "Multiton"

print($"Available keys are: {multiton.getKeys():concat(" ")}")
local s = multiton.getInstance(0)
s:print()
local t = multiton.getInstance(0)
t:print()
print(s == t)                     -- true, same instance
local u = multiton.getInstance(1)
u:print()
print(s == u)                     -- false, different instances
print(instances)                  -- nil
local v = new multiton(3)         -- throws an error
v:print()                         -- not executed
Output:
$ pluto Multiton_user.pluto
Available keys are: 0 1 2
Hello, I'm a multiton for key 0.
Hello, I'm a multiton for key 0.
true
Hello, I'm a multiton for key 1.
false
nil
pluto: ./Multiton.pluto:18: Argument is not a valid key.
stack traceback:
  [C]: in function 'assert'
  ./Multiton.pluto:18: in field '__construct'
  [Pluto-injected code]: in local 'Pluto_operator_new'
  Multiton_user.pluto:15: in main chunk
  [C]: in ?
Works with: Python version 3.x
#!/usr/bin/python

import threading

class Multiton:
    def __init__(self, registry, refnum, data=None):
        with registry.lock:
            if 0 < refnum <= registry.max_instances and registry.instances[refnum] is None:
                self.data = data
                registry.instances[refnum] = self
            elif data is None and 0 < refnum <= registry.max_instances and isinstance(registry.instances[refnum], Multiton):
                self.data = registry.instances[refnum].data
            else:
                raise Exception("Cannot create or find instance with instance reference number {}".format(refnum))

class Registry:
    def __init__(self, maxnum):
        self.lock = threading.Lock()
        self.max_instances = maxnum
        self.instances = [None] * maxnum

reg = Registry(3)
m0 = Multiton(reg, 1, "zero")
m1 = Multiton(reg, 2, 1.0)
m2 = Multiton(reg, 1)
m3 = Multiton(reg, 2)

for m in [m0, m1, m2, m3]:
   print("Multiton is {}".format(m.data))


# produce error
#m2 = Multiton(reg, 3, [2])

# produce error
# m3 = Multiton(reg, 4, "three")

# produce error
# m5 = Multiton(reg, 5)

Tried to translate the C# example at WP but not sure if my interpretation/implementation is correct

# 20211001 Raku programming solution 

enum MultitonType < Gold Silver Bronze >;

class Multiton { 

   my %instances = MultitonType.keys Z=> $ ⚛= 1 xx * ;

   has $.type is rw; 

   method TWEAK { $.type = 'Nothing' unless cas(%instances{$.type}, 1, 0) }
}

race for ^10 -> $i {
   Thread.start(
      sub {
#         sleep roll(^2);
         my $obj = Multiton.new: type => MultitonType.roll;
         say "Thread ", $i, " has got ", $obj.type;
      }
   );
}
Output:
Thread 5 has got Bronze
Thread 9 has got Gold
Thread 7 has got Nothing
Thread 8 has got Nothing
Thread 3 has got Nothing
Thread 2 has got Nothing
Thread 1 has got Nothing
Thread 0 has got Silver
Thread 4 has got Nothing
Thread 6 has got Nothing


Translation of: Java
Rebol [
    title: "Rosetta code: Multiton"
    file:  %Multiton.r3
    url:   https://rosettacode.org/wiki/Multiton
]

;; Define the valid multiton types
multiton-types: [ZERO ONE TWO]

;; Create the instances map and pre-load all available instances
multiton-instances: make map! []

;; Object factory to create a multiton with a given type
make-multiton: func [aType [word!]] [
    make object! [
        type: aType
        to-string: func [] [
            rejoin ["This is Multiton " type]
        ]
    ]
]

;; Pre-load instances for all valid types (analogous to Java's static initializer block)
foreach t multiton-types [
    multiton-instances/:t: make-multiton t
]

;; getInstance equivalent - returns the instance or none if type is not valid
get-instance: func [type [word!]] [
    select multiton-instances type
]

; --- Main ---
alpha: get-instance 'ZERO
beta:  get-instance 'ZERO
gamma: get-instance 'ONE
delta: get-instance 'TWO

print alpha/to-string
print beta/to-string
print gamma/to-string
print delta/to-string
Output:
This is Multiton ZERO
This is Multiton ZERO
This is Multiton ONE
This is Multiton TWO
Works with: Rust
Translation of: C++
use std::collections::HashMap;
use std::sync::{Arc, Mutex, OnceLock};
use std::fmt;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
enum MultitonType {
    Zero,
    One,
    Two,
}

#[derive(Debug)]
struct Multiton {
    multiton_type: MultitonType,
}

impl Multiton {
    // Private constructor
    fn new(multiton_type: MultitonType) -> Self {
        Self { multiton_type }
    }

    // Thread-safe method to get instance
    // Returns None if the type is not found in the map
    pub fn get_instance(multiton_type: MultitonType) -> Option<Arc<Multiton>> {
        static INSTANCES: OnceLock<Mutex<HashMap<MultitonType, Arc<Multiton>>>> = OnceLock::new();
        
        let instances = INSTANCES.get_or_init(|| {
            let mut map = HashMap::new();
            map.insert(MultitonType::Zero, Arc::new(Multiton::new(MultitonType::Zero)));
            map.insert(MultitonType::One, Arc::new(Multiton::new(MultitonType::One)));
            map.insert(MultitonType::Two, Arc::new(Multiton::new(MultitonType::Two)));
            Mutex::new(map)
        });

        let instances_guard = instances.lock().unwrap();
        instances_guard.get(&multiton_type).cloned()
    }

    // Override toString equivalent
    pub fn to_string(&self) -> String {
        let type_str = match self.multiton_type {
            MultitonType::Zero => "ZERO",
            MultitonType::One => "ONE",
            MultitonType::Two => "TWO",
        };
        format!("This is Multiton {}", type_str)
    }
}

// Implement Display trait for easy printing (equivalent to << operator overload)
impl fmt::Display for Multiton {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.to_string())
    }
}

fn main() {
    let alpha = Multiton::get_instance(MultitonType::Zero);
    let beta = Multiton::get_instance(MultitonType::Zero);
    let gamma = Multiton::get_instance(MultitonType::One);
    let delta = Multiton::get_instance(MultitonType::Two);

    if let Some(ref a) = alpha {
        println!("{}", a);
    }
    if let Some(ref b) = beta {
        println!("{}", b);
    }
    if let Some(ref g) = gamma {
        println!("{}", g);
    }
    if let Some(ref d) = delta {
        println!("{}", d);
    }

    // Verify that alpha and beta point to the same instance
    match (alpha, beta) {
        (Some(a), Some(b)) => {
            println!("alpha == beta: {}", Arc::ptr_eq(&a, &b));
        }
        _ => println!("One or both instances are None"),
    }
}
Output:
This is Multiton ZERO
This is Multiton ZERO
This is Multiton ONE
This is Multiton TWO
alpha == beta: true


Library: Wren-dynamic

This more or less follows the lines of the C# example in the linked Wikipedia article.

Although all Wren code runs within the context of a fiber (of which there can be thousands) only one fiber can run at a time and so the language is effectively single threaded. Thread-safety is therefore never an issue.

import "./dynamic" for Enum

var MultitonType = Enum.create("MultitonType", ["zero", "one", "two"])

class Multiton {
    // private constructor
    construct new_(type) {
        _type = type
    }

    static getInstance(type) {
        if (!(0...MultitonType.members.count).contains(type)) {
            Fiber.abort("Invalid MultitonType member.")
        }
        if (!__instances) __instances = {}
        if (!__instances.containsKey(type)) __instances[type] = new_(type)
        return __instances[type]
    }

    type { _type }

    toString { MultitonType.members[_type] }
}

var m0 = Multiton.getInstance(MultitonType.zero)
var m1 = Multiton.getInstance(MultitonType.one)
var m2 = Multiton.getInstance(MultitonType.two)

System.print(m0)
System.print(m1)
System.print(m2)

var m3 = Multiton.getInstance(3)  // produces an error
Output:
zero
one
two
Invalid MultitonType member.
[./multiton line 13] in getInstance(_)
[./multiton line 33] in (script)