どなブロ

エンジニアァのブログです

たのしいRuby 第8章 (2)

クソ長くなった

クラスを拡張する

既存のクラスにメソッドを追加する

  • 既に定義されているメソッドに追記できる
class String
  def count_word
    ary = self.split(/\s+/) # selfを空白文字区切りで配列に分解する
    return ary.size # 分解後の配列の要素数を返す
  end
end

継承する

class クラス名 < スーパークラス名
  クラスの定義
end

Ex)

# 配列サイズより大きなインデックスを指定すると、頭から繰り返して参照する
class RingArray < Array # スーパークラスを指定
  def [](i) # 演算子[]の再定義
    idx = i % size # 新しいインデックスを求める
    super(idx) # スーパークラスの同盟のメソッドを呼ぶ
  end
end
  • 継承を行うことで、複数のクラスの共通部分だけをスーパークラスで実装し、差分はサブクラスで実装するなどできる
  • スーパークラスを指定せずに定義したクラスはObjectクラスの直接のサブクラスとなる
  • Objectクラスが便利にたくさんのメソッドを持っているのに対して、BasicObjectクラスは最低限のメソッドしか持っていない

aliasとundef

alias

  • 既に存在するメソッドに別の名前を割り当てるとき
alias 別名 元の名前   # メソッド名をそのまま書いた場合
alias :別名 :元の名前 # シンボルを使った場合

Ex)

class C1 # C1クラスの定義
  def hello # helloを定義
    "Hello"
  end
end

class C2 < C1 # C1クラスを継承してC2クラスを定義
  alias old_hello hello # 別名old_helloを設定

  def hello # helloを再定義
    "#{old_hello}, again"
  end
end

undef

  • 定義されたメソッドを無かったことにしたいとき
undef メソッド名  # メソッド名そのまま
undef :メソッド名 # シンボルを使う

特異クラス

  • 特異クラス定義を使うと、任意のオブジェクトに、そのオブジェクトだけで利用できるメソッド(特異メソッド)を追加できる。

モジュール

  • モジュールは処理の部分だけをまとめる機能
  • モジュールはインスタンスを持つことができない
  • モジュールは継承できない

モジュールの使い方

Mix-inによる機能の提供

  • モジュールをクラスに混ぜ合わせる事をMix-inという
  • クラス定義の中でincludeを使うとモジュールに含まれるメソッドや定数をクラスの中に取り込む事ができる
  • 以下の場合に継承よりMix-inの方が柔軟に対応できる
    • 2つのクラスは似たような機能を持っているだけで、同じ種類(クラス)と考えたくない
    • Rubyの継承は複数のスーパークラスを持てない仕様になっているため、既に継承を行っていると、うまく共通機能を追加できない

Ex)

module Mymodule
  # 共通して提供したいメソッドなど
end

class MyClass1
  include MyModule
  # MyClass1固有のメソッドなど
end

class MyClass2
  include Mymodule
  # MyClass2固有のメソッドなど
end

名前空間の提供

  • 名前空間…メソッドや定数、クラスの名前を区別して管理する単位
  • モジュールはそれぞれが独立した名前空間を提供する →モジュールA以下のfooメソッドとモジュールB以下のfooメソッドは名前が一緒でも別物
  • モジュールの提供するメソッドは「モジュール名.メソッド名」で参照 →この形式で使用するメソッドをモジュール関数という
  • includeすれば、モジュールの持っているメソッドや定数を現在の名前空間に取り込める

モジュールを作る

  • module文を使う。モジュール名は大文字で始める。
module モジュール名
  モジュールの定義
end

Ex)

module HelloModule # module文
  Version = "1.0" # 定数の定義

  def hello(name) # メソッドの定義
    puts "Hello, #{name}"
  end
  module_function :hello # helloをモジュール関数として公開する
end

メソッドの定義

  • クラスと同様、module文の中でメソッドを定義できる
  • メソッドをモジュール関数として外部に公開する必要がある →module_functionを使用する →module_functionの引数はメソッド名を表すシンボル →公開することによってincludeした先から「モジュール名.メソッド名」の形で呼び出せる

Mix-in

Ex)

module M
  def meth
    "meth"
  end
end

class C
  include M # モジュールMをinclude
end

c = C.new
p c.meth # => meth

→クラスCにモジュールMをインクルードすることで、モジュールMのメソッドをクラスCのインスタンスメソッドとして使える
* includeされているかを調べるには、include?メソッドを使う

C.include(M)  # => true
  • includeされたモジュールは仮想的なスーパークラスとして機能する
  • 継承関係を調べるためには以下
    • ancestorsメソッド…継承関係にあるクラスの一覧取得
    • superclass…直接のスーパークラス
p C.ancestors # => [C, M, Object, Kernel, BasicObject]
p C.superclass # => Object

メソッド検索のルール

  1. 継承の関係と同様、元のクラスで同じ名前のメソッドが定義されている場合はそっち優先
  2. 同じクラスの複数のモジュールをインクルードした場合は、後からインクルードしたもの優先
  3. インクルードが入れ子になった場合も、検索順は一列になる
  4. 同じモジュールを2回以上インクルードしても、2回目以降は無視

extendメソッド

  • モジュールで定義された全てのメソッドを特異メソッドとしてオブジェクトに追加する機能として、Object#extendメソッド
  • extendメソッドではクラスを越えてオブジェクト単位にモジュールの機能を利用できるようになる
module Edition
  def edition(n)
    "#{self}#{n}"
  end
end

str = "たのしいruby"
str.extend(Edition) # => モジュールをオブジェクトにMix-inする

p str.edition(5) # => "たのしいruby 第5版"

クラスとMix-in

  • クラスオブジェクトに対し、extendすることでクラスメソッドを追加できる
  • クラスオブジェクトに対し、includeすることでインスタンスメソッドを追加できる

オブジェクト指向プログラミング

  • オブジェクトとは →プログラムの処理の対象を「オブジェクト」として考える →データやそれを処理する手続きをまとめてオブジェクトとして整理

オブジェクト指向の特徴

  • カプセル化
    • オブジェクトが管理するデータをオブジェクトの外部から直に操作できないようにして、変更・参照する際はかならずメソッドを呼び出させるようにする
    • rubyではオブジェクトの外部からインスタンス変数に直にアクセス出来ないので、元々カプセル化が強制されている
    • 具体的なデータや処理をオブジェクト内部に隠蔽することで抽象的に表現できる →中身を知らなくても使える
  • ポリモーフィズム

ダックタイピング

  • 同じ操作を行えるなら、実際は違うものであってもその違いを気にしない
  • 実際は違うものでも、同じ名前のメソッドを用意することで、処理を共通化できる

感想

  • 間違いなく復習が必要…
  • やっぱりオブジェクト指向よくわかんない、ふんわりとはわかる

以上