includeとextendその2

前回の include は比較的どうでもいい話。

includeは、クラスに対してモジュールのメソッドを追加するので、そのクラスのインスタンスすべてがモジュールのメソッドを使えるようになる。JavaScriptで言えばprototypeにメソッドをセットするようなもの。一方、extendでは、特定のインスタンスに対してモジュールのメソッドを追加する。

module Fuga
    def execute; puts "fuga"; end
end

class Hoge
end

hoge1 = Hoge.new
hoge1.extend Fuga
hoge1.execute        # "fuga"と表示

hoge2 = Hoge.new
hoge2.execute        # NoMethodError

で、extendって何に使うんだという話だが、正直よくわからん。

initialize時に引数によってextendするモジュールのインスタンスの動作を変更してファクトリ不要のテンプレメソッドパターンとシャレこんでみたりする。

class Hoge
    def initialize(sym = nil)
        case sym
        when :a
            self.extend A
        when :b
            self.extend B
        end
    end

    def run
         execute    
    end

    def execute
        puts "default"
    end

    module A
        def execute
            puts "extended A"
        end    
    end
	
    module B
        def execute
            puts "extended B"
        end    
    end
end

Hoge.new.run
Hoge.new(:a).run
Hoge.new(:b).run

だるいので引数にモジュール自体を渡してみる。

class Hoge
    def initialize(mod = nil)
        if not mod.nil? then
            self.extend mod
        end
    end

    # ...  同じなので略

end

Hoge.new.run
Hoge.new(Hoge::A).run
Hoge.new(Hoge::B).run

どことなくprototypeベース的な香りのするmoduleだが、こんな感じで色々遊べそう。継承に頼らずともポリモーフィズムできるのが動的オブジェクト指向の良いところ。それと、extendすると元から持っている同名のメソッドが上書きされるので注意。