how can i extend the singleton pattern to a number of objects for a class i.e. how can i have only 5 objects of a class at max and not more than that in ruby
views:
122answers:
2Multiton with size constraints.
Here is a naive implementation of a Multiton module that you can include in any class. The default number of objects it can create is 5, and you can override this limit by defining a class method called max_instances that returns a number (maximum instances allowed) in your class.
module Multiton
MAX_INSTANCES = 5
COUNT_HOOK = :max_instances
module MultitonClassMethods
def instance
size = @instances.size
max = respond_to?(COUNT_HOOK) ? self.send(COUNT_HOOK) : MAX_INSTANCES
@instances << new if size < max
@instances[rand(size)]
end
end
def self.included(klass)
klass.class_eval {
@instances = []
}
klass.private_class_method :new
klass.extend(MultitonClassMethods)
end
end
Include the module in a class to make it a multiton.
# Falls back to Multiton::MAX_INSTANCES
class Person
include Multiton
end
# Overrides the number of allowed instances in max_instances
class Resource
include Multiton
def self.max_instances
58
end
end
Since the objects are returned randomly from a pool in this multiton, you may not get all the objects back over a short run. But as more objects are requested, it should even out. You can change this behavior in the Multitonmodule by cycling through objects instead of randomly picking one.
people = []
1000.times do
people << Person.instance
end
# should print 5, but may print a smaller number
p people.uniq.size
resources = []
1000.times do
resources << Resource.instance
end
# should print 58, but may print a smaller number
p resources.uniq.size
Example code:
# Example class which can be instanciated at most five times
# Naive approach with Class variable
class FiveAtMost
@@instances = 0
def initialize()
if @@instances >= 5
raise "No more than five instances allowed."
else
@@instances += 1
end
p "Initialized instance #{@@instances}"
end
end
one = FiveAtMost.new
two = FiveAtMost.new
three = FiveAtMost.new
four = FiveAtMost.new
five = FiveAtMost.new
# will raise RuntimeError: No more than five instances allowed.
six = FiveAtMost.new
Since the moment when an object gets garbage collected is not predictable, you'll need some kind of workaround for the that event. Maybe you find this useful: http://pleac.sourceforge.net/pleac_ruby/classesetc.html#AEN710