131

Ruby では、複数の mixin を含めることができますが、1 つのクラスしか拡張できないため、継承よりも mixin が優先されるようです。

私の質問: 役に立つように拡張/インクルードする必要があるコードを書いている場合、なぜそれをクラスにするのでしょうか? または別の言い方をすれば、なぜそれを常にモジュールにしないのですか?

クラスが必要な理由は 1 つだけ考えられます。それは、クラスをインスタンス化する必要がある場合です。ただし、ActiveRecord::Base の場合、直接インスタンス化することはありません。では、代わりにモジュールであるべきではなかったのでしょうか?

4

7 に答える 7

40

ミックスインは素晴らしいアイデアだと思いますが、誰も言及していない別の問題があります: 名前空間の衝突です。検討:

module A
  HELLO = "hi"
  def sayhi
    puts HELLO
  end
end

module B
  HELLO = "you stink"
  def sayhi
    puts HELLO
  end
end

class C
  include A
  include B
end

c = C.new
c.sayhi

どっちが勝つ?Ruby では、 の後にmodule B含めたので、後者の になりますmodule A。これで、この問題を簡単に回避できます。すべてのmodule Amodule Bの定数とメソッドがありそうもない名前空間にあることを確認してください。問題は、衝突が発生したときにコンパイラがまったく警告しないことです。

私は、この振る舞いは大規模なプログラマーのチームには当てはまらないと主張します。実装する人class Cがスコープ内のすべての名前を知っていると想定すべきではありません。Ruby では、別の型の定数やメソッドをオーバーライドすることさえできます。それが正しい動作と見なされるかどうかはわかりません

于 2012-04-26T23:59:32.560 に答える
14

私の見解: モジュールは動作を共有するためのものであり、クラスはオブジェクト間の関係をモデル化するためのものです。技術的には、すべてを Object のインスタンスにして、必要な一連の動作を取得したいモジュールを混在させることができますが、それは貧弱で、でたらめで、かなり読みにくい設計になります。

于 2009-08-15T23:14:02.857 に答える
10

あなたの質問への答えは、主に文脈に依存します。pubb の観察を抽出すると、選択は主に検討中のドメインによって決定されます。

はい、ActiveRecord はサブクラスによって拡張されるのではなく、含まれている必要があります。別の ORMであるdatamapperは、まさにそれを実現します!

于 2009-08-16T09:08:54.480 に答える
4

私はAndy Gaskellの答えがとても好きです-はい、ActiveRecordは継承を使用するのではなく、動作(ほとんどの永続性)をモデル/クラスに追加するモジュールを含める必要があることを追加したかっただけです。ActiveRecord は単に間違ったパラダイムを使用しています。

同じ理由で、私は MongoMapper よりも MongoId を非常に気に入っています。これにより、開発者は問題領域で意味のあるものをモデル化する方法として継承を使用できるようになるからです。

残念なことに、Rails コミュニティで「Ruby 継承」を本来の使用方法 (単に動作を追加するためではなく、クラス階層を定義するため) で使用している人はほとんどいません。

于 2011-04-04T03:21:50.237 に答える