Module: Multiton

Included in:
Infinity
Defined in:
lib/mega/multiton.rb

Overview

:title: Multiton

Multiton module that ensures only one object to be allocated for a given argument list.

The ‘multiton’ pattern is similar to a singleton, but instead of only one instance, there are several similar instances. it’s usefull when you want to avoid constructing objects many times because of some huge expence (connecting to a database for example), require a set of similar but not identical objects, and cannot easily control how many time a contructor may be called.

Synopsis

require 'carat/multiton'

class SomeMultitonClass
  include Multiton
  attr :arg
  def initialize(arg)
    @arg = arg
  end
end

a = SomeMultitonClass.instance(4)
b = SomeMultitonClass.instance(4)	 # a and b are same object
c = SomeMultitonClass.instance(2)  # c is a different object

In previous versions the Class.new method was made private, but for Semi Multitons this restriction has been lifted with the following caveat: Class.instance will attempt to retreive a previously cached object, constructing one if needed, but Class.new will always construct a new object - this should allow great flexiblity with multiton classes.

How It Works

We try to use a previously cached object, if one is not found we construct one and cache it in the pool based on class and the args given to the contructor

note: a limitation of this approach is that it is impossible to detect if different blocks were given to a contructor (if it takes a block. Thus, it is the constructor *args exclusively which determine the uniqueness of an object. A workaround is for the class to define the class method multiton_id, eg:

def Klass.multiton_id(*args, &block)
  # ...
end

Which should return a hash key used to identify the object being constructed as (not) unique.

Author(s)

  • Thomas Sawyer

Defined Under Namespace

Modules: New, Semi

Constant Summary collapse

POOLS =

pools of objects cached on class type

{}
MULTITON_ID_HOOK =

method which can be defined by a class to determine object uniqueness

:multiton_id
MULTITON_NEW_HOOK =

method which can be defined by a class to create multiton objects

:multiton_new

Class Method Summary collapse

Class Method Details

.append_features(klass) ⇒ Object



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/mega/multiton.rb', line 93

def self.append_features(klass)
  klass.private_class_method(:new)
  def klass.instance(*args, &block)
    # if the class defined 'multiton_id' we use this as the key
    # otherwise we simply use the argument list.
    k = (respond_to?(MULTITON_ID_HOOK) ? send(MULTITON_ID_HOOK, *args, &block) : args)
    unless (obj = (POOLS[self] ||= {})[k])
      begin
        critical = Thread.critical
        Thread.critical = true
        meth = self.respond_to?(MULTITON_NEW_HOOK) ? MULTITON_NEW_HOOK : :new
        obj = (POOLS[self][k] = self.send(meth, *args, &block))
      ensure
        Thread.critical = critical # restore state
      end
    end
    return obj
  end
end