読者です 読者をやめる 読者になる 読者になる

Bonkura - Kenny

SIerで働く文系SEの記録

【たのしいRuby_8】クラス・オブジェクト指向

たのしいRubyの第8章を学んだ。オブジェクト指向を理解する為に大事な内容が詰まっていた。

たのしいRuby 第4版

たのしいRuby 第4版

基本的な用語整理

  • クラス:オブジェクトの種類を表す。雛形・設計図・型みたいなもの。Rubyではオブジェクトは例外なく何らかのクラスに属している。
  • 継承:既に定義されているクラスを拡張して新しいクラスを作ること。
  • サブクラス:継承によって新しく作られたクラス。Rubyの全てのクラスはBasicObjectクラスのサブクラスになっている。
  • スーパークラス:継承のもとになったクラス

クラス

クラス判別メソッド(Objectクラスで定義されている。)

  • instance_of?メソッド:オブジェクトがそのクラスに所属しているか知る
  • is_a?メソッド:継承関係を更にさかのぼってクラスにそのクラスに属しているか調べる

クラスを作る

class クラス名
 クラスの定義
end
# クラス名は大文字から始める。

クラスがnewされたら。。。

下記の場合、インスタンス変数である@nameが"Bob"で初期化される。

〜〜
def initialize(muname="Ruby")
@name = myname
end
〜〜
Hello.new("Bob")

インスタンス変数:@変数名

同じインスタンス内であればメソッド定義を超えてその値を参照できる!

アクセスメソッド

オブジェクトの外部からインスタンス変数にアクセスする事が出来ない為、そのためのメソッドが必要。インスタンス変数name「@name」に対して…

  • attr_reader :name 参照のみ可能。
  • attr_writer :name 書き込みのみ可能
  • attr_accessor :name 参照書き込み可能

上記は、下記を省略した書き方である。

def name
  @name
end

def name=(value)
  @name = value
end
〜
p Hello.name
p Hello.name="Bob"

インスタンスメソッドの中で、メソッドのレシーバ自身のインスタンス変数を参照する

def greet
 puts self.name ※selfは実行メソッドのレシーバ。この場合はputs name でも変わらん
 self.name=test ※name=test だとローカル変数nameに代入することになるのでNG
end

クラスメソッド

クラスそのものをレシーバとするメソッド。newしてインスタンスを生成する必要なし。

class <<  HelloWorld
  def hello(name)
    puts "#{name} Hello"
  end
end

HelloWorld.hello("Ken")

定数

p HelloWorld::Version #=> "1.0"

クラス変数:@@で始まる

そのクラス全てのインスタンスで共有できる変数のこと

メソッドの呼び出すを制限する

無闇にインスタンスメソッドを呼びだされたくない場合の事を考え、3種類のアクセス制限のレベルがある。

def pubend
public :pub

def priend
private :pri

クラスを拡張する

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

aliasとundef

モジュール

  • 処理の部分だけをまとめる機能
  • インスタンスを持つことが出来ない
  • 継承出来ない

名前空間

  • Aというモジュールのfooメソッドと、Bというモジュールのfooメソッドは別のものとして扱われる。
  • モジュール内部に名前を定義する事で、名前の競合を防ぐ事が出来る。
  • includeを使うことで、モジュールが持っているメソッド名や定数名を現在の名前空間に取り込める。
p Math::PI
p Math.sqrt(2)

include Math
p PI
p sqrt(2)

モジュールの作成

module HelloModule
  Version = "1.0"

  def hello(name)
    puts "Hello, #{name}"
  end
  # モジュール名.メソッド名の形式で呼び出せるように外部に公開する。
  module_function :hello
end

p HelloModule::Version
HelloModule.hello("Alice")

Mix-in

モジュールをクラスに混ぜ合わせること。クラス定義の中でincludeを使うとモジュールに含まれるメソッドや定数をクラスの中に取り込む事が出来る。

  • クラスは複数スーパークラスを持つことが出来ない(単純継承)ので、複数の機能を共有したい場合に柔軟に対応出来る
  • 同じ機能を持っているけど、同じ種類(クラス)だと考えたくない。

Mix-inした時のメソッド検索のルール

  • Mix-inしても元のクラスで同じ名前のメソッドが定義されいる場合はそちら優先
  • 同じクラスに複数のモジュールをインクルードした場合は、後からインクルードしたもの優先
  • 同じモジュールを2回以上インクルードした場合、2回め以降は無視

オブジェクト指向用語

カプセル化

オブジェクトが管理するデータをオブジェクトの外部から直に操作出来ないようにして、変更したり参照したりするときは必ずメソッドから呼び出すようにする。不整合なデータがオブジェクトに設定されプログラムの挙動がおかしくなる事を防ぐ。

ポリモルフィズム

1つのメソッド名が複数のオブジェクトに属する(そのオブジェクトによって異なる結果が得られる)こと。同じto_sメソッドを使っても、レシーバによって返る値はぜんぜん違うよね。