さわって学ぶオブジェクト指向 ― クラス・カプセル化・継承・ポリモーフィズム
ゲームのキャラと介護記録を例に、オブジェクト指向の4つの考え方を、その場で書き換えて実行できるコードで学びます。最後に、問題と答え・解説も読めます。
オブジェクト指向は、プログラムを「もの(オブジェクト)」の集まりとして組み立てる考え方です。このページのコードは、その場で書き換えて実行できます。数字や名前を変えて、結果がどう変わるか試してみてください。
console.log の結果が下に出ます。ここに結果が出ます
クラスとオブジェクト
クラスは設計図、オブジェクト(インスタンス)は設計図から作った実物です。「ペンギン」という設計図から、「ペン太」と「ペン子」を作れます。2匹は同じ形ですが、HP はそれぞれが自分の分を持っています。ペン子が攻撃されても、ペン太の HP は減りません。
- 属性(フィールド):持っているデータ。名前、HP
- メソッド:できること。攻撃する、話す
new:設計図から実物を作る(インスタンス化)
カプセル化
データを外から直接書き換えられないようにして、決めた入口(メソッド)からだけ変えられるようにする考え方です。介護記録で体温を「100度」と打ち間違えても、入口でチェックすればはじけます。中身を隠すことを情報隠蔽とも言います。
使う側は「どう記録しているか」を知らなくても、setTemperature を呼ぶだけで済みます。中の作りをあとで変えても、使う側のコードは変えずに済みます。
継承
親クラスの属性とメソッドを受け継いで、違うところだけ書き足すしくみです。「キャラクター」を親にすれば、ペンギンもロボットも「あらわれた!」の処理を書き直さずに使えます。親と同じ名前のメソッドを書き直すことをオーバーライドと言います。
継承は「ペンギンはキャラクターである」(is-a)が自然に言えるときに使います。「ペンギンは装備を持っている」(has-a)なら、継承ではなく、装備をフィールドとして持たせます。
ポリモーフィズム(多態性)
同じ speak() を呼んでも、相手がペンギンなら「ペンペン」、ロボットなら「ピポパ」と、相手ごとに違う動きになります。呼ぶ側は相手の種類で場合分けしなくていいので、新しいキャラを足すときも、呼ぶ側のコードはそのままです。
C# と Java では
考え方は同じで、書き方が少し違います。
C#
class Penguin : Character // 継承は「:」
{
private int hp = 100; // private で外から隠す
public override void Speak() // 上書きは override
{
Console.WriteLine("ペンペン!");
}
}Java
class Penguin extends Character { // 継承は extends
private int hp = 100; // private で外から隠す
@Override
public void speak() { // 上書きの印 @Override
System.out.println("ペンペン!");
}
}| JavaScript | C# | Java | |
|---|---|---|---|
| 継承 | extends | : | extends |
| 隠す | #名前 | private | private |
| 上書き | 同じ名前で書くだけ | virtual / override | @Override(付けるのが基本) |
問題と、答え・解説
試験の過去問ではなく、このページ用に作った問題です。
同じ Penguin クラスから a と b を作りました。a.hp を 10 減らすと、b.hp も減りますか?
答え:減らない。オブジェクトは、それぞれ自分のデータを持っています。設計図(クラス)が同じでも、実物(インスタンス)は別々です。
体温を外から直接書き換えられないようにして、チェック付きのメソッドからだけ変えられるようにしました。この考え方は何ですか?
答え:カプセル化(情報隠蔽)。おかしな値を入口ではじけるうえ、中の作りを変えても使う側に影響しません。
Penguin は Character を継承しています。Penguin に greet() を書いていないのに、p.greet() を呼ぶとどうなりますか?
答え:親(Character)の greet() が動く。子に無いメソッドは親から探されます。子で同じ名前を書けば、子のほうが優先されます(オーバーライド)。
チームの全員に speak() を呼んだら、種類ごとに違うセリフになりました。if で種類を調べていません。このしくみの名前は?
答え:ポリモーフィズム(多態性)。新しい種類を足しても、呼ぶ側のループは書き換えずに済みます。
「ペンギンはキャラクターである」と「ペンギンは装備を持っている」。継承で表すのに向いているのはどちらですか?
答え:「である」(is-a)のほう。UML では汎化と呼びます。「持っている」(has-a)は集約・コンポジションで、装備をフィールドとして持たせます。
次に読む
各言語の基本文法は、コード解説の記事にまとめています。打って覚えたいときはコードタイピングへ。
コード解説:基本文法を読む →