From: David Garamond Date: 2004-06-08T17:47:08+09:00 Subject: Implementing interface using classes (Re: Interfaces and semantics) Let's say I want to implement interfaces using classes (so I can do interface checking with the simple Object#kind_of?). There will be components (which will also be classes). A component can implement one or more interfaces. Method names from different interfaces might clash (e.g. IFoo#quack vs IBar#quack) and we need to be able to choose which interface we want to use from a component. What's the best way to implement this? My current attempt: --- BEGIN OF CODE --- # components will derive from the Component class, to share # some common code class Component # @implements will contain a list of interfaces that this component # implements def Component.implements; @implements end def implements; self.class.implements end def Component.implements?(itf); @implements.include? itf end def implements?(itf); self.class.implements? itf end # @implementors is a hash, containing the class that implements a # certain interface. def Component.implementors; @implementors end def implementors; self.class.implementors end # will return an instance of implementor class def use_interface(itf, *args) raise ArgumentError unless implements? itf raise NotImplementedError unless implementors[itf] implementors[itf].new(*args) end end # IHasFeet is an interface class IHasFeet # s is speed def walk(s); raise NotImplementedError end # d is the name of a dance def entertain(d); raise NotImplementedError end end # IHasMouth is an interface class IHasMouth # sp is speed, str is string def talk(sp, str); raise NotImplementedError end # s is the name of a song def entertain(s); raise NotImplementedError end end # Human is a component. It implements IHasFeet and IHasMouth. class Human < Component @implements = [IHasFeet, IHasMouth] class Human_IHasFeet < IHasFeet def walk(s); puts "Walking..." end def entertain(d); puts "Can't dance!" end end class Human_IHasMouth < IHasMouth def talk(sp, str); puts str end def entertain(s); puts "Singing #{s}..." end end @implementors = {IHasFeet => Human_IHasFeet, IHasMouth => Human_IHasMouth} end # Bear is a component. It implements IHasFeet and IHasMouth. class Bear < Component @implements = [IHasFeet, IHasMouth] class Bear_IHasFeet < IHasFeet def walk(s); puts "Walking..." end def entertain(d); puts "Dancing #{d}..." end end class Bear_IHasMouth < IHasMouth def talk(sp, str); puts "R O A R!" end def entertain(s); puts "Can't sing!" end end @implementors = {IHasFeet => Bear_IHasFeet, IHasMouth => Bear_IHasMouth} end # test p Bear.implements # -> [IHasFeet, IHasMouth] p Bear.implements? IHasMouth # -> true bear = Bear.new p bear.implements # -> [IHasFeet, IHasMouth] p bear.implements? IHasFeet # -> true b = bear.use_interface(IHasFeet) p b.kind_of? IHasFeet # -> true b.walk(1) # -> Walking... b.entertain("russian dance") # -> Dancing russian dance... b = bear.use_interface(IHasMouth) b.entertain("o canada") # -> Can't dance! --- END OF CODE --- The code feels very mechanic and contains a lot of plumbing, but it's pretty much what I wanted (my requirements): a) a component can implement multiple interfaces; b) I can pick interfaces from components without fear of conflict; c) my other code can later check whether something has a feet or a mouth, without explicitly checking its component class (Human or Bear). Any better suggestion? -- dave