Как вы получаете доступ к переменной экземпляра в методе mixin? - PullRequest
14 голосов
/ 19 февраля 2010

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

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

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

пример

self.do_something(self.text)

или

@thing.do_something(@thing.text)

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

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

Ответы [ 3 ]

24 голосов
/ 19 февраля 2010

В общем, избегайте использования 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"

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

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"

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

class Foo

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

end

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

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 голосов
/ 19 февраля 2010

Имена переменных экземпляра начинаются с ruby ​​с @ например. @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
1 голос
/ 19 февраля 2010

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

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

def text
    @text ||= ""
end
...