From: Massimiliano Mirra Date: 2003-01-21T02:14:12+09:00 Subject: Re: a single class that supports multiple facets/interfaces David Garamond writes: > if a client wants interface 1, then she will get the methods foo and bar > (which is actually C#bar1). if he picks interface 2, then she will get > the methods foo and bar (which is actually C#bar2). for all she cares, > she just wants to know/deal with a single [versatile] class, C. and from > that single class, she can pick several sets of features/interfaces she > needs/wants. > > i know that, in ruby, modules are usually used for things like this, but > in my case many of the method names are the same so i don't think > modules are approriate for this. for example, interface1 consists of > foo, bar, baz, abc, and abd. interface2 consists of foo, bar, baz, bab, > bac. in most of the cases all of the interfaces provide the same set of > features, just in a different style or different revision. > > any pointers of how i might do something like this in ruby? I know that you're avoiding inheritance on purpose, but I'd do it like this: class C def self.new(facet = 1, *args) if self == C case facet when 1 then C1.new(*args) when 2 then C2.new(*args) end else super(*args) end end def foo puts "foo" end def bar1 puts "bar version 1" end def bar2 puts "bar version 2" end end class C1 < C alias_method :bar, :bar1 end class C2 < C alias_method :bar, :bar2 end c1 = C.new(1) # cilent1 picks interface as defined in C1 c1.foo # prints "foo" c1.bar # prints "bar version 1" c2 = C.new(2) # client2 picks interface as defined in C2 c2.foo # prints "foo" c2.bar # prints "bar version 2" You can define a class method in C named .facet if you don't want to touch .new for this purpose, just rename .new. def self.facet(facet = 1, *args) if self == C case facet when 1 then C1.new(*args) when 2 then C2.new(*args) end else super(*args) end end And can easily take away the ugly case statement, too: def self.facet(facet = 1, *args) if self == C Object.const_get("#{self}#{facet}").new(*args) else super(*args) end end Finally, you might want to make it generally useful by stuffing it into a mixin: module Facetable def facet(facet = 1, *args) if self == C Object.const_get("#{self}#{facet}").new(*args) else super(*args) end end end class C extend Facetable ... end class C1 < C ... end class C_something < C ... end c1 = C.facet(1) csth = C.facet("_something") ....and so on. Massimiliano