How do you access an instance variable within a mixin method? I can think of 2 ways, but both seem problematic.
Have the mixin method access the instance variable directly as any class method would, e.g self.text. Problem with this开发者_Go百科 is that it places restrictions on where the mixin method can be used, and forces the class doing the mixing to have a particular instance method named in a particular way.
Pass the instance variable as a parameter to the mixin method, which would result in code like this:
example
self.do_something(self.text)
or
@thing.do_something(@thing.text)
which looks nasty to me, and doesn't conform to the principles of object orientation.
Is there any other way to do it?, am I right to be concerned?
In general, avoid having mixins access member variables: It's a very tight form of coupling that can make future refactoring unnecessarily difficult.
One useful strategy is for the Mixin to always access variables via accessors. So, instead of:
#!/usr/bin/ruby1.8
module Mixin
def do_something
p @text
end
end
class Foo
include Mixin
def initialize
@text = 'foo'
end
end
Foo.new.do_something # => "foo"
the mixin accesses the "text" accessor, which is defined by the including class:
module Mixin
def do_something
p text
end
end
class Foo
attr_accessor :text
include Mixin
def initialize
@text = 'foo'
end
end
Foo.new.do_something # => "foo"
What if you need to include the Mixin in this class?
class Foo
def initialize
@text = "Text that has nothing to do with the mixin"
end
end
Using generic and common data names in mixins can lead to conflicts when the including class uses the same name. In that case, have the mixin look for data with a less common name:
module Mixin
def do_something
p mixin_text
end
end
and let the including class define the appropriate accessor:
class Foo
include Mixin
def initialize
@text = 'text that has nothing to do with the mixin'
@something = 'text for the mixin'
end
def mixin_text
@something
end
end
Foo.new.do_something # => "text for the mixin"
In this way, the accessor acts as sort of "impedance matcher" or "translator" between the mix-in's data and the including class's data.
Instance variable names start in ruby with an @ eg. @variable
. You can acces them with this name from a Module you include
module M
def t
@t
end
end
class A
include M
def initialize(t)
@t= t
end
end
A.new(23).t # => 23
If you wan't to access @t
when it's not defined in your class before you can do it this way
module M
def t
instance_variable_defined?("@t") ? @t : nil
end
end
You can provide this instance method yourself in this module, but you have to be careful not to overwrite existing method
Example (in module you are mixing in):
def text
@text ||= ""
end
精彩评论