ホーム DoRuby includeとextend
includeとextend
 

includeとextend

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

今回は、includeとextendについて調べてみました。

include, extendとは

 include,extendは、モジュールのメソッドをクラスに読み込む機能を持っています。異なる点は、includeがインスタンスメソッド、extendがクラスメソッドとしてクラスに読み込みます。コードでは、以下のようになります。

module Dog
  def dog
    'Bow wow'
  end
end

class IncludeDog
  include Dog
end

class ExtendDog
  extend Dog
end

include_dog = IncludeDog.new
include_dog.cry
=> "Bow wow"

ExtendDog.cry
=> "Bow wow" 

 extendは、クラスのインスタンスに対して実行することもできます。この場合、実行したインスタンスにのみ、extendしたモジュールのメソッドが使用することができます。クラスのインスタンスに対してextendした場合は、特異メソッドとして取り込まれます。

module Dog
  def cry
    'Bow wow'
  end
end

class Animal
end

animal = Animal.new
animal.extend Dog
animal.cry
=>"Bow wow"

 includeにもextendと同様に、インスタンスを使用した方法があります。

animal = Animal.new
class << animal
  include Dog
end
animal.cry
=>"Bow wow"

モジュール読み込みとオーバーライドについて

 モジュールとクラスに同じメソッドが存在した場合、include, extendを行うことでどちらのメソッドがオーバーライドされるのか気になったので調べてみました。結果は、クラス内でinclude, extendした場合は、クラスで定義したメソッドが呼び出され、クラスのインスタンスを使用してinclude,extendした場合は、モジュールで定義したメソッドが呼び出されました。

enter image description here

 クラス内でinclude, extendした場合に、クラスのメソッドを上書きしてモジュールのメソッドを呼び出す方法が無いか調べてみると、includeの代わりにprependを使用することで解決できることが分かりました。includeとprependの違いは、継承される順番が異なることです。includeの場合だと「クラス < モジュール」、prependだと「モジュール < クラス」となります。

module Dog
  def cry
    'module method'
  end
end

class PrependDog
  prepend Dog

  def cry
    'prepend dog'
  end
end

prepend_dog = PrependDog.new
prepend_dog.cry
=> "module method"

# PrependDogの親クラス一覧 一番左が自分のクラス、右が親クラス
PrependDog.ancestors
=> [Dog, PrependDog, ..., Object, BasicObject]

まとめ

今回は、includeとextendについてまとめてみました。

  • インスタンスメソッドとして取り込むならinclude
  • クラスメソッドとして取り込むならextend
  • インスタンスに対してinclude, extendを行うことでクラスのメソッドを上書きする(メソッド名が重複する場合)
  • prependで、クラスのメソッドを上書きする(メソッド名が重複する場合)
記事を共有

最近人気な記事