未経験からプログラミング学習に励んでおります。
楽しいこと大好き、自由を求める『Tatooo』です。
『えっ?クラスって何!?』
プログラミング(Ruby)が楽しくなって、どんどんカリキュラムを進めていると、『クラス』や『インスタンス』、『継承』といった初学者には難しい概念が出てきました。
インプット学習しているだけでは理解できそうにないので、『鉄は熱いうちに打て!』ということで学習した内容を自分なりにイメージして記事に残してみようと思います。
(記事を書いてみるということ自体が挑戦なので、拙い文章ですがご了承ください・・・言い訳)
1.Rubyにおける『クラス』と『インスタンス』の概念
まずは教科書的な説明から。
- すべてのデータは
『オブジェクト』である
⇨ Rubyで扱うあらゆるデータはオブジェクトという実体である -
クラス=設計図・インスタンス=実体
⇨ クラスという型を元に、具体的なインスタンスを作成する - 同じ機能を持つ実体を簡単に
複製できる
⇨ 1つのクラスから同じ構造・機能を持つ実体を何個でも簡単に生成できる
2.なぜクラスを難しく感じるのか
おそらくクラスの概念で躓く初学者は多いと思います。では、何故難しく感じてしまうのでしょうか。理由を考えてみました。
- クラス周辺で初めて聞く用語が多い
- 「設計図」と「実体」と言われてもイメージが湧きにくい
- 上から下へ実行される(逐次処理)はずなのに、なぜ下で定義したメソッドを上で使えるの?と勘違いする
3.例えでイメージしてみる
イメージがつきにくい概念は自分が理解しやすいイメージに置き換えて考えてみると良いと言います。なので、自分なりに『例え話』を作って考えてみました。
『天地創造』
クラス(設計図)やインスタンス(実体)の概念について、神が人を創るという『天地創造』の考え方がしっくりくるのではないだろうか。
〜〜〜背景〜〜〜
今パソコンをカタカタと打っている私は神である。人間というものを創ろうとしているが、複数の人間をゼロから創るのは超めんどくさい。だから、最初に人間の型を用意して、それを複製しようと考えた。
1.神が人間の型(クラス)を定義する
まず『人間とはこういうもの』という型を創ろう!
# 神様が用意した「人間の型(設計図)」
class Human
end
2.型から実体の人間であるアダムとイシャー(インスタンス)を生成する
よし、この型から1人目の人間(adam)を誕生させよう!
# 神様が型を元に『adam』という実体を生み出した!
adam = Human.new
おぉ!簡単に創れた!ならば、同じように2人目の人間(イシャー)も誕生させてしまえ!
# 神様が型を元に『ishah』という実体を生み出した!
ishah = Human.new
3.自動で出生手続きを行う仕組みを作る
名前がないと個人の区別がつかないな……よし、誕生した瞬間に自動で名前を登録する出生手続きの仕組みを作ろう!(これがinitializeメソッド)
class Human
# new された瞬間に自動で動く「初期化」の処理
def initialize(name)
@name = name # 個別の名前を @name にセット
end
end
# 神が「アダム」と「イシャー」を誕生させる(ここでinitializeが自動実行される!)
adam = Human.new("アダム")
ishah = Human.new("イシャー")
補足説明
@ がつく変数は「インスタンス変数」と呼ばれ、そのオブジェクトごとに独立して保持されるデータ(アダムやイシャーの心の中のデータ)です。
4.自己紹介をさせる
名前を与えて誕生させたものの、このままだと名前が心の中( @ name )にあるだけで外からは見えないな。自分の名前を周囲に教えるための口( getter )を作ってあげよう。
class Human
def initialize(name)
@name = name
end
# getter:周りの人に自分の名前を教える口
def name
@name
end
end
adam = Human.new("アダム")
# アダムが周囲に向かって『アダム』と名乗る!
puts adam.name # => "アダム"
5.氏名変更に対応する窓口を作る
イシャーはイヴという名前に改名することとなったのか。それなら、氏名変更に対応する窓口を作ろう。
class Human
def initialize(name)
@name = name
end
# getter:周りの人に自分の名前を教える口
def name
@name
end
# setter:新しい名前を受け取って、心の中(@name)で更新する
def name=(new_name)
@name = new_name
end
end
ishah = Human.new("イシャー")
# イシャーの名前を「イヴ」に変更する
ishah.name = "イヴ"
# 名前が変わったか確認
puts ishah.name # => "イヴ"
補足説明
毎回 def name や def name=(new name) を書くのは大変なので、この getter と setter をたった1行で自動生成してくれる attr_accessor という魔法のような仕組みが存在します。だが、裏では『心の中のデータを教える口( getter )と『データを書き換える窓口( setter )』が働いているということを理解しておくことが大切です。
6.人間の共通機能を持った『子ども』という型を創る
Human という型(クラス)で人間が創れたのはいいけど、同じような人間ばかりだとつまらないな。よし、この Human の型にある基本機能は引き継いだままで Child という別の型を創ってみよう。
# 親クラス(Human)を attr_accessor でスッキリさせた状態
class Human
attr_accessor :name
def initialize(name)
@name = name
end
end
# 親クラス(Human)を継承して Child クラスを生成する
class Child < Human
# 親の機能(initializeやname)はそのまま使える
def play
"#{name}は元気に遊んでいる!"
end
end
cain = Child.new("カイン")
# 親のgetterがそのまま使える
puts cain.name # => "カイン"
# 子ども(Child)だけの独自機能も使える
puts cain.play # => "カインは元気に遊んでいる!"
補足説明
Child クラスの中には initialize を書いていません。しかし、親である Human の機能を継承しているため、Child.new ("カイン")とするだけで親の initialize が自動的に呼び出されて名前が登録されます。
そして、神である私は創造主として意気込むのであった
この人間クラスと子どもクラスを使って、これからも個性的な人間をたくさん創っていくぞ!!
To be continued no more・・・
4.なぜ「下で定義したメソッド」が「上」で使えるように感じるのか?
プログラミングは基本的に「上から1行ずつ実行」されます。しかし、クラスを書く作業は 実行ではなく「設計図(神の知識)を登録している作業」 です。
神が Human という設計図の中に『歩く』『食べる』といった機能を後(下)から追加定義しても、設計図が完成した後に誕生したアダムやイシャー(イヴ)は、そのすべての機能を使うことができます。
「上から順に実行されている」のではなく、「設計図を読み込んでから、実体を作って動かしている」からこそ起こる勘違いだということです。
5.まとめ
このように、一見難しく見えるクラスや継承の概念も例え話を用いてイメージしてみると理解しやすく感じました。
- クラスは実体を作るための型(HumanやChild)
- インスタンスはクラスから生成された実体(adamやcain)
- initializeメソッド:インスタンスが生成された時に自動で初期化されるメソッド
- getter:心の中の値を外部から読み取ることができる機能
- setter:心の中の値を外部から変更することができる機能
- attr_accessor:getterとsetterを簡単に実装できる機能
- 継承:親クラスの機能を引き継いで新たにクラスを作ること
最後まで読んでくださってありがとうございました!