Techioz Blog

mixin メソッド内でインスタンス変数にアクセスするにはどうすればよいですか?

概要

mixin メソッド内でインスタンス変数にアクセスするにはどうすればよいですか? 2つの方法が考えられますが、どちらも問題があるようです。

self.do_something(self.text)

または

@thing.do_something(@thing.text)

これは私には不快に思えますし、オブジェクト指向の原則にも準拠していません。

他に方法はありますか?心配しても大丈夫ですか?

解決策

一般に、ミックスインがメンバー変数にアクセスできるようにすることは避けてください。これは非常に密接な結合形式であり、将来のリファクタリングを不必要に困難にする可能性があります。

有用な戦略の 1 つは、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"

このクラスに Mixin を含める必要がある場合はどうすればよいでしょうか?

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"

このように、アクセサーは、ミックスインのデータとそれを含むクラスのデータの間で、一種の「インピーダンス マッチャー」または「トランスレーター」として機能します。