我希望能够来回切换实例如何响应消息。我希望通过混合模块,然后在另一个模块中混合来覆盖该行为来做到这一点。
示例:
module Dog
def speak
puts "woof woof"
end
end
module Cat
def speak
puts "meow"
end
end
class Animal
end
现在我想来回切换Animal
的实例如何响应speak
消息:
animal = Animal.new
animal.extend(Cat)
animal.speak
animal.extend(Dog)
animal.speak
animal.extend(Cat)
animal.speak
animal.extend(Dog)
animal.speak
animal.extend(Cat)
animal.speak
我希望此代码输出以下内容:
meow
woof woof
meow
woof woof
meow
相反,它输出如下:
meow
woof woof
woof woof
woof woof
woof woof
有关如何使其按预期工作的任何提示?
答案 0 :(得分:4)
我在Adapter Pattern in ruby: Accessing Your Instance Variables
的另一个问题上调整了答案module Dog
def speak
puts "woof woof"
end
end
module Cat
def speak
puts "meow"
end
end
module Module_manager
attr_accessor :name
def extend mod
@ancestors ||= {}
return if @ancestors[mod]
remove @name if @name
@name = mod
mod_clone = mod.clone
@ancestors[mod] = mod_clone
super mod_clone
end
def remove mod
mod_clone = @ancestors[mod]
mod_clone.instance_methods.each {|m| mod_clone.module_eval {remove_method m } }
@ancestors[mod] = nil
end
end
class Animal
include Module_manager
end
animal = Animal.new
animal.extend(Cat)
animal.speak # meow
animal.extend(Dog)
animal.speak # woof woof
animal.extend(Cat)
animal.speak # meow
animal.extend(Dog)
animal.speak # woof woof
animal.extend(Cat)
animal.speak # meow
答案 1 :(得分:2)
我不确定以下内容是否能回答您的问题,但这是实现相同行为的更简单方法。
class Animal
include Dog
alias :dog_speak :speak
include Cat
alias :cat_speak :speak
private :dog_speak, :cat_speak
def initialize
@speak_to_me = [:cat_speak, :dog_speak].cycle
end
def speak
send @speak_to_me.next
end
end
animal = Animal.new
#=> #<Animal:0x007fe3a222b0e0 @speak_to_me=#<Enumerator:
# [:cat_speak, :dog_speak]:cycle>>
animal.speak #-> meow
animal.speak #-> woof woof
animal.speak #-> meow
animal.speak #-> woof woof