Как получить доступ к переменной экземпляра в методе mixin?

Как вы получаете доступ к переменной экземпляра в методе mixin? Я могу думать о двух путях, но оба кажутся проблематичными.

  • Попросите метод mixin получить доступ к переменной экземпляра напрямую, как любой метод класса, например self.text. Проблема заключается в том, что он устанавливает ограничения на то, где можно использовать метод mixin, и заставляет класс, выполняющий микширование, иметь конкретный метод экземпляра, названный определенным образом.

  • Передайте переменную экземпляра в качестве параметра методу mixin, который приведет к следующему коду:

Пример

self.do_something(self.text)

или

@thing.do_something(@thing.text)

который выглядит противно мне и не соответствует принципам объектной ориентации.

Есть ли другой способ сделать это? Я прав, чтобы вас беспокоило?

Ответ 1

В общем, избегайте использования переменных-членов mixins: это очень плотная форма связи, которая может сделать ненужным сложную работу в будущем.

Одна полезная стратегия заключается в том, что Mixin всегда получает доступ к переменным через аксессуар. Итак, вместо:

#!/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"

mixin обращается к "текстовому" аксессуру, который определяется классом включения:

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"

Что делать, если вам нужно включить Mixin в этот класс?

class Foo

def initialize
  @text = "Text that has nothing to do with the mixin"
end

end

Использование общих и общих имен данных в mixins может привести к конфликтам, когда класс включения использует одно и то же имя. В этом случае попросите mixin искать данные с менее распространенным именем:

module Mixin

  def do_something
    p mixin_text
  end

end

и включите класс включения соответствующего аксессора:

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"

Таким образом, аксессор действует как своего рода "согласование импеданса" или "переводчик" между данными смешения и включенными данными класса.

Ответ 2

Имена переменных экземпляра начинаются с ruby ​​с помощью @eg. @variable. Вы можете использовать их с этим именем из модуля, который вы включаете

module M
  def t
    @t
  end
end

class A
  include M
  def initialize(t)
     @t= t
  end
end

A.new(23).t # => 23

Если вы не получите доступ к @t, если он не определен в вашем классе, прежде чем вы сможете это сделать

module M
  def t
    instance_variable_defined?("@t") ? @t : nil
  end
end

Ответ 3

Вы можете предоставить этот метод экземпляра самостоятельно в этом модуле, но вы должны быть осторожны, чтобы не перезаписывать существующий метод

Пример (в модуле, в котором вы смешиваете):

def text
    @text ||= ""
end