継承とミックスイン
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ともできる。
モジュールの中でクラスを定義すれば、「モジュール名:: クラス名」でクラスを参照できる。
あとクラスの中でクラスも定義できるよ。
本記事は下記本の勉強記事です。初学者にとても良い本です。