4

メソッドを「パーソナル」にする方法を探しています-クラスにプライベートではないことに注意してください

ここに例があります-「個人的」とは、メソッド「foo」の動作を意味します

class A
  def foo
     "foo"
  end
end

class B < A
  def foo
      "bar"
  end
end

class C < B
end

a=A.new; b=B.new;c=C.new

私は次の動作を生成する方法を探しています

a.foo #=> "foo"

b.foo #=> "bar"

c.foo #=> "foo" (ultimate base class method called)
4

6 に答える 6

3

「個人的な」メソッドを作成する代わりに、継承構造を変更してください。

A クラスに変更を加えずに、C クラスには B クラスと同じ機能の一部のみを持たせたいようです。

class A
  def foo
     "foo"
  end
end

class BnC < A
end

class B < BnC
  def foo
      "bar"
  end
end

class C < BnC
end

a=A.new; b=B.new;c=C.new
于 2010-03-31T20:43:59.893 に答える
2

混乱する可能性があるようですが、次の1つのオプションがあります。

class A
  def foo
     "foo"
  end
end

class B < A
 def initialize #when constructing, add the new foo method to each instance
    def self.foo
      "bar"
    end 
 end
end

class C < B
 def initialize #when constructing, do nothing
 end
end

より一般的には、同様のアプローチを使用して、特定のインスタンスにメソッドをいつでも追加できます。もちろん、継承されたクラスや同じクラスの他のインスタンスには影響しません。

最終的に達成しようとしていることの詳細を教えていただければ、おそらくもっと役立つ可能性があります。

于 2010-03-31T20:55:06.720 に答える
2

これを行う標準的な方法はありません。継承の仕組みを回避します。B のメソッドを実装して、次のようなロジックを実行できます。

def foo
  instance_of?(B) ? "bar" : super
end

publicもちろん、 and と同様にこれを行う Class のメソッドを定義することもできますprivate

class Class
  def personal(*syms)
    special_class = self
    syms.each do |sym|
      orig = instance_method(sym)
      define_method(sym) {|*args| instance_of?(special_class) ? orig.bind(self).call(*args) : super}
    end
  end
end

次にpersonal :foo、 と同じように B でできますprivate :foo

(これはまったく最適化されておらず、私はゼロ引数の動作を実装していませんpublicprivate率直に言って、正しく行うのは巨大な PITA であり、それでもハックです。)

于 2010-03-31T20:17:07.753 に答える
0

実際に何を達成したいのかよくわからないので、これに答えるのは少し難しいですが、次のようなことを試すことができます

class C < B
  def foo
    self.class.ancestors[-3].instance_method(:foo).bind(self).call
  end
end

ancestors[-3]AがObjectとKernelを継承し、最上位の非組み込みクラスからメソッドにアクセスすることを目的としていることを前提としています。もちろんself.class.ancestors[-3]、単にA、で置き換えるか、配列からクラスを自分で把握することもできancestorsます。)

実際には、元のファイルをB変更できる場合は、元のクラスでエイリアスを作成する方が簡単です(つまりalias :foo_from_A :fooclass B < A新しいの前に、を呼び出すことがdef fooできます)。または、で必要なものを再定義します。または、クラス階層全体を別の方法で設計します。foo_from_ACC

于 2010-03-31T20:54:31.930 に答える
0

パーソナル化メソッドを処理するショートカット関数を作成できます。

def personalize(*methodNames)
  old_init = instance_method(:initialize)
  klass = self
  modul = Module.new {
    methodNames.each { |m|
      define_method(m, klass.instance_method(m)) if klass.method_defined?(m)
    }
  }
  methodNames.each { |m| 
    remove_method(m) if method_defined?(m)
  }
  define_method(:initialize) { |*args|
    # I don't like having to check instance_of?, but this is the only way I 
    # could thing of preventing the extension of child classes. At least it only
    # has to happen once, during initialization.
    extend modul if instance_of?(klass)
    old_init.bind(self).call(*args)
  }
  self
end

class A
  def foo
     "foo"
  end
end

class B < A
  def foo
      "bar"
  end
  def bam
    'bug-AWWK!'
  end
  personalize :foo, :bam, :nometh
end

class C < B
end

a=A.new; b=B.new; c=C.new
a.foo #=> "foo"
b.foo #=> "bar"
b.bam #=> "bug-AWWK!"
c.foo #=> "foo"
C.instance_method(:foo) # => #<UnboundMethod: C(A)#foo>
c.bam #throws NoMethodError
于 2010-03-31T23:22:27.353 に答える
0

"is a" (継承) 関係が本当に必要ない場合があります。時々あなたが望むのは「クワックのような音」です。モジュールを使用してメソッドを「ミックス」することにより、「いんちきのような」クラス間でコードを共有するのは簡単です。

#!/usr/bin/ruby1.8

module BasicFoo
  def foo
     "foo"
  end
end

class A
  include BasicFoo
end

class B
  def foo
      "bar"
  end
end

class C
  include BasicFoo
end

p A.new.foo    # => "foo"
p B.new.foo    # => "bar"
p C.new.foo    # => "foo"
于 2010-04-01T20:30:53.167 に答える