Multiton: Difference between revisions
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
- 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
- produce error
- m3 = Multiton(reg, 4, "three")
- 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
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)