13

クラス A と B は同一です。

class A < ActiveRecord::Base
 def foo
  puts "foo"
 end
end

class B < ActiveRecord::Base
 def foo
  puts "foo"
 end
end

このようなリファクタリングと基本クラスの違いは何ですか:

class Base < ActiveRecord::Base
 def foo
  puts "foo"
 end
end

class A < Base
end

class B < Base
end

ベースモジュールを使用してこのように:

module Base
 def foo
  puts "foo"
 end
end

class A < ActiveRecord::Base
 include Base
end

class B < ActiveRecord::Base
 include Base
end

ある方法は別の方法よりも望ましいですか?

4

5 に答える 5

24

これらの2つの方法には、他のすべての答えが欠落しているという根本的な違いがあります。それは、STI(Single Table Inheritance)のrailsの実装です。

http://api.rubyonrails.org/classes/ActiveRecord/Base.html(「単一テーブル継承」セクションを検索)

基本的に、次のようにBaseクラスをリファクタリングする場合:

class Base < ActiveRecord::Base
  def foo
    puts "foo"
  end
end

class A < Base
end

class B < Base
end

次に、「bases」というデータベーステーブルがあり、「type」という列があり、値は「A」または「B」である必要があります。このテーブルの列はすべてのモデルで同じになり、モデルの1つだけに属する列がある場合は、「ベース」テーブルが非正規化されます。

一方、Baseクラスを次のようにリファクタリングすると、次のようになります。

Module Base
  def foo
  puts "foo"
 end
end

class A < ActiveRecord::Base
 include Base
end

class B < ActiveRecord::Base
 include Base
end

その場合、テーブルの「ベース」はありません。代わりに、テーブル「as」とテーブル「bs」があります。それらが同じ属性を持っている場合、列は両方のテーブル間で複製される必要がありますが、違いがある場合、それらは非正規化されません。

したがって、一方が他方よりも好ましい場合はそうですが、それはアプリケーションに固有です。経験則として、それらがまったく同じプロパティまたは大きな重複を持っている場合は、STI(1番目の例)を使用します。それ以外の場合は、モジュール(2番目の例)を使用します。

于 2009-11-11T00:23:14.853 に答える
5

これらの方法はどちらも機能します。モジュールまたはクラスを使用することを決定するとき、私が持っている質問は、クラスがオブジェクト階層に適合するか、またはこれらが再利用しようとしているメソッドだけかということです。DRY の理由で一般的なコードを除外しようとしているだけなら、それはモジュールのように聞こえます。それだけで意味のある階層に収まるクラスが本当にある場合は、クラスを使用します。

Java のバックグラウンドを持っているので、これらの決定を下すことができるのは新鮮です。

于 2009-11-10T16:40:39.070 に答える
4

モジュールの柔軟性が向上します。モジュールの意図は、さまざまなタイプのクラスにまたがることです。もう 1 つの方法では、自分自身を Base にロックします。それ以外は、大きな違いはありません。

多重継承に対する Ruby の答えはミックスインです。クラスはすでに Rails 固有のクラスを継承しているため、カスタム クラスを継承することはできません。

したがって、あなたの選択は、長いチェーンで一緒にチェーンするか、よりクリーンで理解しやすい mixin を使用することです。

于 2009-11-10T16:41:55.583 に答える
1

モジュールは、1) 1 つのクラスからのみ継承できますが、複数のモジュールを含めることができ、2) スーパークラスを継承せずに基本クラスから継承することはできませんが、モジュールをすべて含めることができるという点で、より柔軟性があります。 (たとえば、アクティブなレコード モデルではない別のクラスに「foo」メソッドを追加したい場合があります)。

もう 1 つの違いは、クラス Base のメソッド内では、ActiveRecord::Base から何かを呼び出すことができましたが、モジュールからそれを行うことができなかったことです。

于 2009-11-10T16:40:43.103 に答える
1

それはあなたが本当にやろうとしていることによります。

  1. メソッドのオーバーライドまたは ActiveRecord::Base への追加: アプリ内のすべての ActiveRecord モデルをrespond_to foo.
  2. ActiveRecord::Base をサブクラス化し、すべてのモデルがサブクラスから継承するようにします: 1 と同じ結果が得られますが、アプリ内のすべてのモデルは型にはまらないクラスを拡張する必要があるため、わざわざ面倒なことをする必要はありません。
  3. include module : これは、一部のモデルのみが にアクセスする必要がある場合に効果的fooです。これは、ほとんどすべてのacts_as_<whatever>プラグインが行うことです。

要するに、すべてのモデルに ActiveRecord::Base が既に提供しているものとは異なる動作を持たせたい場合は、オプション 1 を使用します。少数のモデルのみが動作を必要とする場合は、モジュールを作成してモデルに含めます (オプション 3) )。

于 2009-11-10T16:41:28.850 に答える