2012-10-16 14 views
5

クラスとインスタンスの両方のメソッドを持つFlightというモジュールがあるとします。Rubyモジュールの継承がクラス継承のように機能しないのはなぜですか?

class Bat < Mammal 
    # Add Flight's class methods to Bat. 
    extend Flight 

    # Add Flight's instance methods to Bat. 
    include Flight 
    ... 
end 

includeBat.ancestorsFlightを追加しますが、extendはしません:私はincludeextend、またはその両方を使用してクラスにそのメソッドを取得することができます。

私の質問は、です。これは、モジュールと比べてなぜ、クラスと違うのですか? Mammalをサブクラス化すると、I は常にとなり、クラスメソッドとインスタンスメソッドの両方を同時に取得できます。しかし、私は(私はActiveSupport::Concernようself.includedフックか何かを使用しない限り)I が一度に両方のクラスとインスタンスメソッドを取得することはできません、モジュールに混ぜます。

この違いの後ろに言語設計の問題はありますか?

+1

エンティティ、そうですか? :) –

答えて

3

オブジェクトとしてBatクラスもMammalシングルトンクラスからインスタンスメソッドを継承しているためだ

「私はMammalのサブクラスを作成するとき、私は常に、一度にクラスとインスタンスメソッドの両方を取得します」。クラスへのモジュールを含む

Inheritance Graph

方法は、チェーンを見て変更します。実際には、クラスはインスタンスメソッドを継承しません。

モジュールとクラスを拡張する任意のオブジェクトを拡張と同じです。クラスは単にモジュールのインスタンスメソッドをクラスインスタンスメソッド(つまりクラスオブジェクト自体のメソッド)として取得します。私はあなたの質問の一部に対処したいと思います

3

includeBat.ancestorsFlightを追加しますが、extendはしません。

を拡張と同じがそれは明らかに異なる何かをするが含まれていない...あなたはと考えることができに等しいを拡張するクラスのメタクラスにが含まれます。 がメタクラスにを含めるように、あなたは、拡張モジュールがメタクラス祖先チェーンで現れて見ている拡張するので、だから、

module M 
end 

class A 
    include M 
end 

# then you will see M within A's ancestors as you know 
A.ancestors # => [A, M, Object...] 


class B 
    # the following is roughly the same as extend M: 
    class <<self 
    include M 
    end 
end 

# then you will see M within B's metaclass' ancestors 
MetaclassOfB = class <<B; self; end 
MetaclassOfB.ancestors # => [M, Class, Module...] 

..:

は、次の例を見てください。

10

両方Module#includeObject#extendObjectインスタンスメソッドModuleを追加するために使用されます。

module Flight 
    def can_fly? 
     true 
    end 
end 

Module#include追加(またはでミックス)するために使用されるクラスまたはモジュールのインスタンスメソッドへのモジュールのインスタンスメソッド:

class Bat < Mammal 
    include Flight 
end 

a = Bat.new() 
a.can_fly?  # true 

実際にモジュールを考える したがって、Object#is_a?方法に影響を与える:

a.is_a? Flight  # true 

Module#includeでありますプライベートメソッド、クラス又は別のモジュールを定義するときにのみ関数表記で呼び出すことができるように:

class Bat < Mammal 
    self.include Flight  # NoMethodError: private method called 
end 

Object#extendは、それがだれているオブジェクトにシングルトン方法としてモジュールのインスタンスメソッドを追加あなたがこれを行うことができますので、と呼ばれる:

b = Mammal.new() 
b.extend Flight 
b.can_fly?   # true 
b.is_a? Flight  # true 

c = Mammal.new() 
c.can_fly?   # NoMethodError: undefined method 

をそしてだけbFlightからインスタンスメソッドを持っています。他のMammalオブジェクトはありません。

Object#extendをクラス定義内で呼び出すと、メソッドは定義しているクラスの固有クラスに追加されます。 クラス定義の内部でそれらを使用するときにメソッドがクラスメソッドとして追加されているので、これは、2つの方法の間の重要な違いです:まあ、別々の存在を正当化するために、いくつかの違いが存在しなければならない

class Bat < Mammal 
    extend Flight 
end 

Bat.can_fly?  # true 

d = Bat.new 
d.can_fly?  # NoMethodError: undefined method 
関連する問題