【12日目③:Rubyの継承とミックスイン!!】改訂3版基礎Ruby on Railsを読んだで!

シェアする

  • このエントリーをはてなブックマークに追加
41AkxXsz+5L._SX258_BO1,204,203,200_

継承とミックスイン

Rubyには既存のクラスを拡張する方法がいろいろある・
オブジェクトと指向プログラミングでは標準的なクラスの継承と、
Rubyの特徴であるミックスインがある。

継承

継承は既存のクラス(親クラス)を元に新しいクラス(サブクラス)を作成し、
親クラスの機能をそっくり取り込む方法です。

サブクラスに機能を追加すれば親クラスとサブクラスの機能の両方が使えるようになる。
サブクラスは「class サブクラス名 < 親クラス名」と記述する。

例:親クラスRobot、サブクラスFlyingRrobot

class FlyingRobot < Robot
end

FlyingRobotクラスにzという属性をつけてみる。
moveメソッドでは親クラスの属性x,yを取り扱えるようにする。zは高さを表す。
下記例のsuperは親クラスの同名メソッドを呼び出すもの

super(x,y)とすることでRobotクラスのmoveメソッドを呼び出せば
「@x += x; @y += y」を繰り返し書かなくて良い。
※位置の値を変更するときに。
また、「@z += z」を加えるとmoveメソッドの機能を拡張できる。

class FlyingRobot < Robot
  def move(x, y, z)
    super(x, y)
    @z += z
  end
end

実際にクラスの承継のサンプルはこちら

class Robot
  def initialize(name)
    @name = name
    @x = @y = 0
  end

  def move(x, y)
    @x += x; @y += y
  end

  def to_s
    "#{@name}: #{@x},#{@y}"
  end
end

class FlyingRobot < Robot
  def initialize(name)
    super
    @z = 0
  end

  def move(x, y, z)
    super(x, y)
    @z += z
  end

  def to_s
    super + ",#{@z}"
  end
end

robo1 = FlyingRobot.new("飛行ロボ1号")
robo1.move(20, 10, 30)
puts robo1

Robotクラスを継承してFlyingRobotクラスを作り、
FlyingRobotクラスに新しい機能を追加した。

サブクラスのメソッドの引数が親クラスと同じ時には、superの引数を省略できる。
※FlyingRobotクラスのinitializeでsuperとなっているがこれはsuper(name)と同じこと。

superは、クラスを継承したときに、同じ親クラスの同名メソッドを小クラスのメソッドのなかで実行する。だから同じ名前で定義してあげないとだめ。

Objectクラスについて

class クラス名 ~ endで記述した次アクのクラスは
自動的にObjectクラスのサブクラスになる。

StringやFixumのような組み込みのクラスもObjectクラスのサブクラス。
階層関係はクラスの種類によって変わる

例:Fixum<Integer<Numeric<Object<BasicObject

自作クラスも組み込みクラスもインスタンスはobject_idなどのメソッドを呼び出せるのは親クラスのObjectクラスのメソッドだから。

Rubyでのモジュールとミックスイン

モジュールとはクラスに似たもので、「module モジュール名 ~ end」で
モジュールを定義し、その中にメソッドを記述できる。

モジュールをメソッドにまとめておくとその機能を
クラスに取り入れてクラスの機能を拡張できる。

クラスにモジュールを組み込むことをミックスインという。
モジュールとクラスの違いは継承ができないこととnewで
インスタンスが作成できないことです。

モジュールは親クラスにはなれないし親クラスを持てない。でもミックスインできる。
クラスの継承は単一継承なので複数の親クラスを持つサブクラスを作れない。

モジュールは複数のモジュールをクラスに取り込むことができる。

例:ロボット間の距離を計算して返すメソッドdistance_toを備えるRadarモジュールをRobotクラスに取り込む(ミックスイン)

するとする。

module Radar
  def distance_to(other)
    Math.sqrt((self.x - other.x) ** 2 + (self.y - other.y) ** 2)
  end
end

class Robot
  include Radar
  attr_accessor :name, :x, :y

  def initialize(name)
    @name = name
    @x = @y = 0
  end

  def move(x, y)
    @x += x; @y += y
  end

  def to_s
    "#{@name}: x = #{@x}, y = #{@y}"
  end
end

robo1 = Robot.new("ロボ1号")
robo2 = Robot.new("ロボ2号")
robo2.move(12, 35)
puts "距離は #{robo1.distance_to(robo2)} です。" # Radarのインスタンスメソッドを利用している。

「include Radar」のようにincludeにモジュールを指定する

するとRadarのインスタンスメソッドを利用することができる。

dhistance_toメソッドを利用するにはRadarモジュールを取り込むクラスのObjectが属性xとyを持っている必要がある。

モジュールの方のメソッドようわからん
→106に書き込みしてる。ここで使ってるの平方根の定理だからややこしい(笑)

モジュールは名前空間としても使える

モジュールはミックス員の他に名前空間としても使うkともできる。
モジュールの中でクラスを定義すれば、「モジュール名:: クラス名」でクラスを参照できる。
あとクラスの中でクラスも定義できるよ。

本記事は下記本の勉強記事です。初学者にとても良い本です。

スポンサーリンク
Sponsored Link
Sponsored Link

シェアする

  • このエントリーをはてなブックマークに追加

フォローする

スポンサーリンク
Sponsored Link