2章 月曜日: オブジェクトモデル
オブジェクトモデル
全ての 言語要素(クラス、モジュール、インスタンス変数 etc...)が共存しているシステムのこと。
以下の2つの質問に答える場所
- このメソッドはどのクラスに所属するものなのか
- このモジュールをincludeしたら何が起きるのか
2.1 オープンクラス
オープンクラス
- いつでも既存のクラスを再オープンして、そのばで修正できる技法のこと
- (既存クラスには、String,Arrayなど標準クラスも含む)
classキーワード
-
クラス宣言。主な仕事はクラスのコンテキストに連れて行くこと。 -
Rubyではクラスを定義するコードと、その他のコードに違いはない。
モンキーパッチ
-
オープンクラスを否定的に言う、蔑称。
-
何も考えずにクラスにコードを追加することで、既存のメソッドを上書きし、意図しない挙動を生み出すこと。
-
Refinementsを使うことで、安全にモンキーパッチを利用できるようになる。
2.2 オブジェクトモデルの内部
インスタンス変数
-
オブジェクトに存在する
-
値が代入されたときに初めて出現する
- Rubyのオブジェクトのクラスと、インスタンス変数には何のつながりもない!
-
メソッドを呼び出さなければ、インスタンス変数は存在しない。
class MyClass
def my_method
@v = 1
end
end
obj = MyClass.new
obj.instance_variables => []
obj.my_method => 1
obj.instance_variables => [:@v]
メソッド
-
メソッドはオブジェクトではなく、クラスに存在する
- オブジェクトにはメソッドはなく、インスタンス変数とクラスへの参照があるだけ
クラスとは
-
クラスはClassクラスのオブジェクト
- オブジェクトのメソッド → そのクラスのインスタンスメソッド
- クラスのメソッド → Classクラスのインスタンスメソッド
-
全てのクラスは、モジュールである
- クラスとは、インスタンスの生成と継承のための3つのメソッドをもつモジュール
- クラス名は、定数
定数
- 大文字で始まる参照は、クラス名やモジュール名を含めて、全て定数
- プログラムにある全ての定数は、ファイルシステムのようにツリー状に配置
- モジュール: ディレクトリ / 定数: ファイル
- 定数ツリーの奥にいるときは、ルートを示すコロン2つで書き始めれば、外部の定数を絶対パスで指定できる
Y = 'ルートレベルの定数'
module M
Y = 'Mにある定数'
Y #=> "Mにある定数"
::Y #=> "ルートレベルの定数"
end
オブジェクトとクラスのまとめ
オブジェクト
- インスタンス変数の集まりにクラスへのリンクがついたもの
インスタンスメソッド
- オブジェクトではなく、オブジェクトのクラスに住む
クラス
- オブジェクトにインスタンスメソッドの一覧とスーパークラスのリンクがついたもの
クラス名
クラスへのアクセスを行うための参照
2.4 メソッドを呼び出すときに何が起きているの?
- メソッドを探す。メソッド探索
- メソッドを実行する。selfが必要
メソッド探索
- Rubyがレシーバのクラスに入り、メソッドを見つけるまで、継承チェーンを上ること。
「右へ一歩、それから上へ」
- レシーバのクラスに向かって右へ一歩進み、メソッドが見つかるまで継承チェーンを上へ進む。
レシーバ
- 呼び出すメソッドが属するオブジェクト
継承チェーン
- スーパークラスを、BasicObjectまで続けたとき、通ったクラスの道筋のこと
モジュールとメソッド探索
- モジュールをクラスにインクルードすると、Rubyはモジュールを継承チェーンに挿入する
- include: インクルードしたクラスの上にモジュールが挿入される
- Prepende: 下にモジュールが挿入される
Kernal
- Objectクラスが、Kernelモジュールをincludeしているので、全てのオブジェクトの継承チェーンに、Kernelモジュールが挿入される
メソッドの実行
selfキーワード
- メソッドを呼び出すとき、メソッドのレシーバがselfになる
- レシーバを明示しないメソッド呼び出しは、全てselfに対する呼び出しになる。
- 他のオブジェクトを明示してメソッドを呼び出すと、今度はそのオブジェクトがselfになる
- 最後にメソッドのレシーバとなったオブジェクトが、selfとなる
トップレベル
- メソッドを呼び出さないときselfになるのは、Objectクラスのインスタンスの
main
self #=> main
self.class #=> Object
クラス定義とself
- クラスやモジュールの定義の内側(メソッドの外側)では、selfの役割はクラスやモジュールそのもの
class MyClass
self #=> MyClass
end
Refinements
- Refinementsが有効になる場所
- refineブロック
- usingを呼び出した場所からモジュールの終わりまで(モジュール定義にいる場所 / ファイルの終わりまで(トップレベルにいる場合)
- クラスをリファインすると言うのは、元のコードにパッチを貼り付けるようなもの
- リファインされた側のクラスよりも優先される
- インクルードやプリペンドしたものより優先される
感想
これまで、オブジェクトがメソッド・変数を持つと、漠然とまとめて理解していたので、インスタンス変数は、オブジェクトに存在する
/ メソッドはオブジェクトではなく、クラスに存在する
と整理できたのがかなり、すっきりきたーーーー(ような気がする。)