= Multiton The Multion pattern is essentially the same as the Singleton pattern, but unlike it's fully unique brethren Multiton's are identical if their initialization parameters are identical. To demontrate we first need to load the Facets multiton.rb script. require 'facets/multiton' Now for the various exmples. == EXAMPLE A - STANDARD USAGE 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 a.assert == b x = [a.arg, b.arg].max * 10 + c.arg x.assert == 42 == EXAMPLE B - MODIFY AN EXISTING CLASS We can modify an existing class (if we are so bold), for example we can add shared filehandles to the File class. class ::File include Multiton end lineno = __LINE__ # HERE1 # HERE2 a = File.instance(__FILE__) b = File.instance(__FILE__) b.assert == a lineno.times{ a.gets } a.gets.strip.assert == "# HERE1" b.gets.strip.assert == "# HERE2" == EXAMPLE C - INHERITENCE class A < String include Multiton end # B is also a multiton - with it's OWN object cache class B < A; end # w is the same object as x, y is the same object as z w,x,y,z = A.instance('A'), A.instance('A'), B.instance('B'), B.instance('B') x.object_id.assert == w.object_id z.object_id.assert == y.object_id a = B.instance('A') b = B.instance('A') w.object_id.refute == a.object_id # (each class has it's own pool) b.object_id.assert == a.object_id == EXAMPLE D - MULTIPLE MODULE INCLUSION (does nothing) class A < String include Multiton end # B is also a multiton - with it's OWN object cache class B < A; end # w is the same object as x, y is the same object as z w,x,y,z = A.instance('A'), A.instance('A'), B.instance('B'), B.instance('B') yz_id = y.object_id || z.object_id If we include Multiton again, it will have to effect. B.class_eval { include Multiton } # y is not only the same object as z, but they are both the same object(s) # as from EXAMPLE C y,z = B.instance('B'), B.instance('B') yz_id.assert == y.object_id yz_id.assert == z.object_id == EXAMPLE E - SO YOU WANNA USE NEW INSTEAD OF INSTANCE module K # use an inner class which is itself a multiton class K < String; include Multiton; end # define a new which returns a mutltion using #instance... class << self def new(*args, &block) K.instance(*args, &block) end end end the = K.new '4' answer = K.new '2' x = sprintf( "%s%s", the, answer ) x.assert == "42" the.class.assert == K::K == EXAMPLE F - using Klass.multiton_id class Klass include Multiton def initialize( important, not_important ) @important, @not_important = important, not_important end def Klass.multiton_id(*args, &block) # we consider only the first arg important, not_important = *args important end end a = Klass.instance( :a, :b ) b = Klass.instance( :a, :c ) c = Klass.instance( :b, :b ) a.assert == b c.refute == a c.refute == b