我正在研究ruby中的adapter 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
实例方法的任何提示?我认为问题是我的适配器方法是类级方法。
谢谢!
答案 0 :(得分:2)
您需要将模块用作mixin并提供一种方法来跟踪哪个模块处于活动状态,这些方法似乎不会被重新包含或重新扩展覆盖,因此我采用了我发现的扩展和删除方法{{ 3}}
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!
答案 1 :(得分:1)
这是因为function requestToServer(lParamList: TStringList) : string;
var
Params: TStringList;
Thread: TThread;
begin
Params := TStringList.Create;
try
Params.Assign(lParamList);
except
Params.Free;
raise;
end;
TThread.CreateAnonymousThread(
procedure
var
lHTTP: TIdHTTP;
serverResponce : string;
aObj: ISuperObject;
begin
try
try
lHTTP := TIdHTTP.Create(nil);
try
serverResponce := lHTTP.Post('http://domain.com/mjson.php', lParamList);
aObj := SO(serverResponce);
if aObj['result'].AsString = 'lr_102' then
begin
TThread.Queue(nil,
procedure
begin
form2.Label3.Text := 'Saved token expired.';
form2.Rectangle2.Visible := true;
end
);
end
else if aObj['result'].AsString = 'lr_103' then
begin
X := aObj['dta'].AsArray;
TThread.Queue(nil,
procedure
begin
form2.Label3.Text := 'Auto login.';
//load device data
form2.allDeviceListData := X;
form2.Hide;
form1.show;
end
);
end;
// globalReachedServer := true;
finally
lHTTP.Free;
end;
finally
Params.Free;
end;
except
TThread.Queue(nil,
procedure
begin
form2.Memo1.Lines.Add('errr');
end
);
end;
end
).Start;
end;
上下文中的name
指的是与您期望的module
完全不同的内容。 name
类和Animal
模块不共享数据,它们没有任何关系。巧合的是,你正在调用Module#name
碰巧返回Cat
,因为那是模块的名称。
为了解决这个问题,你需要做两件事之一。您可以将Adapter::Cat
混合(删除module
,然后根据需要self
)或通过将其作为参数传递给include
来共享必要的数据。< / p>
第一种方法如下:
speak
这看起来并不简单,因为它们基本上生活在两个不同的世界中。这是一种更像Ruby的方式:
module Adapter
module Dog
def self.speak(name)
puts "#{name} says: woof!"
end
end
end
class Animal
attr_accessor :name
attr_reader :adapter
def initialize(name)
@name = name
self.adapter = :dog
end
def speak
self.adapter.speak(@name)
end
def adapter=(adapter)
@adapter = Adapter.const_get(adapter.to_s.capitalize)
end
end