Multiton: Difference between revisions

From Rosetta Code
Content added Content deleted
m (→‎{{header|Wren}}: Correction to preamble.)
(julia example)
Line 13: Line 13:
* [[Singleton]]
* [[Singleton]]
<br><br>
<br><br>


=={{header|Julia}}==
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.
<lang julia>struct Multiton{T}
data::T
function Multiton(registry, refnum, data)
if 0 < refnum <= registry.max_instances && registry.instances[refnum] isa Nothing
lock(registry.spinlock)
multiton = new{typeof(data)}(data)
registry.instances[refnum] = multiton
unlock(registry.spinlock)
return multiton
else
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)
</lang>{{out}}
<pre>
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
</pre>

=={{header|Wren}}==
=={{header|Wren}}==
{{libheader|Wren-dynamic}}
{{libheader|Wren-dynamic}}

Revision as of 00:40, 14 September 2021

Multiton is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.
Description

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

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




Julia

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. <lang julia>struct Multiton{T}

   data::T
   function Multiton(registry, refnum, data)
       if 0 < refnum <= registry.max_instances && registry.instances[refnum] isa Nothing
           lock(registry.spinlock)
           multiton = new{typeof(data)}(data)
           registry.instances[refnum] = multiton
           unlock(registry.spinlock)
           return multiton
       else
           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

  1. produce error
  2. m3 = Multiton(reg, 4, "three")
  1. produce error

m5 = Multiton(reg, 5)

</lang>

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

Wren

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. <lang ecmascript>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</lang>

Output:
zero
one
two
Invalid MultitonType member.
[./multiton line 13] in getInstance(_)
[./multiton line 33] in (script)