我正在学习适配器模式 https://www.sitepoint.com/using-and-testing-the-adapter-design-pattern/在红宝石中的实现。我想访问适配器模块定义中的实例变量。看一下下面的代码:
module Adapter
module Dog
def self.speak
# I want to access the #name instance variable from my Animal instance
puts "#{name} says: woof!"
end
end
module Cat
def self.speak
# I want to access the #name instance variable from my Animal instance
puts "#{name} says: meow!"
end
end
end
class Animal
attr_accessor :name
def initialize(name)
@name = name
end
def speak
self.adapter.speak
end
def adapter
return @adapter if @adapter
self.adapter = :dog
@adapter
end
def adapter=(adapter)
@adapter = Adapter.const_get(adapter.to_s.capitalize)
end
end
为了测试它,我做了以下操作:
animal = Animal.new("catdog")
animal.adapter = :cat
animal.speak
我希望它返回以下内容:
catdog says: meow!
相反,它说:
Adapter::Cat says: meow!
有关如何访问的任何提示Animal#name
适配器模块的实例方法?我认为问题在于我的适配器方法是类级方法。
Thanks!
您需要将模块用作 mixin 并提供一种方法来跟踪哪个模块处于活动状态,这些方法似乎不会通过重新包含或重新扩展而被覆盖,因此我采用了我发现的扩展和删除方法here https://www.ruby-forum.com/topic/164431.
module Adapter
module Dog
def speak
puts "#{name} says: woof!"
end
end
module Cat
def speak
puts "#{name} says: meow!"
end
end
def extend mod
@ancestors ||= {}
return if @ancestors[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 Adapter
attr_accessor :name, :adapter
def initialize(name)
@name = name
@adapter = Adapter::Dog
extend Adapter::Dog
end
def adapter=(adapter)
remove @adapter
extend Adapter::const_get(adapter.capitalize)
@adapter = Adapter.const_get(adapter.capitalize)
end
end
animal = Animal.new("catdog")
animal.speak # catdog says: woof!
animal.adapter = :cat
animal.speak # catdog says: meow!
animal.adapter = :dog
animal.speak # catdog says: woof!
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)