プログラムを「もの」と「できること」で整理する考え方がオブジェクト指向です。
本記事では、初心者の方でもつまずきにくいように、カプセル化、継承、多態性の3つの柱を日常のたとえと図解の代わりになる文章でやさしく説明します。
読み終えるころには、クラスやオブジェクトの役割が自然にイメージできるようになります。
オブジェクト指向とは
オブジェクト指向(OOP)のねらい
オブジェクト指向(Object Oriented Programming, OOP)のねらいは、複雑な問題を小さな部品に分けてわかりやすくし、変更や拡張に強い設計を作ることにあります。
ひとまとまりの「もの」ごとにデータと処理を一緒に持たせることで、全体の複雑さを局所化できるのが特徴です。
なぜ初心者に向くのか
人はもともと身の回りの物事を「もの」として考えるため、OOPは自然な発想の流れに沿っています。
クラスが設計図、オブジェクトが実物という比喩で学べるため、用語さえ覚えれば理解が加速します。
クラスとオブジェクトの違い
クラスは設計図、オブジェクトはその設計図から作られた実体です。
同じクラスから何個でもオブジェクトを作れますが、クラス自体は1つの定義として存在します。
具体的な違いを整理
クラスとオブジェクトの違いを次の表にまとめます。
| 観点 | クラス | オブジェクト |
|---|---|---|
| 役割 | 設計図 | 実物 |
| 中身 | プロパティの型やメソッドの定義 | 実際の値や振る舞い |
| 数 | 1つの定義でOK | 必要な数だけ生成 |
| 例 | 車という設計図 | 赤い車、青い車など |
クラスは「どう振る舞うべきか」を定義し、オブジェクトは「実際にどう振る舞うか」を担います。
プロパティ(データ)とメソッド
プロパティはオブジェクトが持つデータ、メソッドはそのデータを使って行う処理です。
状態(プロパティ)と振る舞い(メソッド)が一緒に存在することで、オブジェクトは主体的に動ける単位となります。
注意: 単なるデータ袋ではない
データと処理はセットで意味を持ちます。
プロパティだけが外から好き放題に変えられると、矛盾が起きやすく設計が壊れやすくなります。
オブジェクト指向のたとえ
家電製品のリモコンを思い浮かべてください。
ユーザーはボタンを押すだけで、内部の複雑な仕組みを知らなくても使えます。
オブジェクト指向では、外から触れるボタンの部分がインターフェースで、内部の仕組みは隠されています。
誤解しやすいポイント
「現実世界そっくり」に作る必要はありません。
プログラムにとって役立つ部分だけを抽象化するのがコツです。
カプセル化の基本
カプセル化とは何か
カプセル化は、オブジェクトの内部状態を隠し、外部には必要な操作だけを見せる考え方です。
中身を守り、正しい方法でしか変更できないようにすることで、データの整合性と安全性を確保します。
例: 銀行口座
「残高」は外から直接書き換えられず、「入金」や「出金」の操作だけが公開されます。
これにより、残高がマイナスになるなどの不正な状態を防げます。
公開範囲(public/private)の考え方
公開範囲は、どのコードからアクセスできるかを決める仕組みです。
基本は最小限だけを公開し、内部の詳細は非公開にします。
よく使う公開レベルのざっくり比較
| レベル | 外からの見え方 | 使いどころ |
|---|---|---|
| public | どこからでも見える | 外部に使ってほしい操作 |
| private | 同じクラスの中だけ | 内部の詳細や補助処理 |
| protected | 子クラスからは見える | 継承前提の内部処理 |
まずはprivateをデフォルトにし、必要になったらpublicに広げる発想が安全です。
ゲッター/セッターで安全に扱う
ゲッターは値を取り出す窓口、セッターは値を設定する窓口です。
セッターで不正な値を弾いたり、値の変更に合わせた処理を挟んだりできます。
バリデーションを入れられる理由
「年齢は0以上」「メールは正しい形式」といった条件をセッターに置けば、どこから設定されても安全です。
データのルールを1か所に集めることで、保守が一気に楽になります。
カプセル化のメリット
カプセル化により、誤った使い方を防ぎ、内部の変更が外部に波及しにくくなります。
外から見える部分が安定していれば、内部の実装を自由に改善できるのが大きな利点です。
初学者が感じやすい効果
コードを読むとき、外から利用可能なメソッドだけを追えばよいので理解の負担が下がります。
「どこから触られるかわからない不安」が減り、バグの原因を絞り込みやすくなります。
よくあるつまずき
- なんでもpublicにしてしまう: 使い勝手はよく見えますが、外からの無秩序な変更で不具合の温床になります。最小公開の原則を習慣化しましょう。
- ゲッター/セッターの乱用: 何でもゲッター/セッターにすると、結局「どこでも変更できる」に近づきます。本当に必要な操作だけを公開するのがポイントです。
- 状態を直接いじるユーティリティ: 別クラスから内部をこっそり変えるのは避けましょう。一貫した窓口を通すことが大切です。
継承の基本
継承とは何か
継承は、既存のクラスの性質を引き継ぎ、共通部分を再利用しつつ差分を追加する仕組みです。
重複を減らし、共通のふるまいを1か所で管理できます。
例: 乗り物の階層
「乗り物」を親クラスとして、「車」「自転車」などを子クラスにします。
共通の移動メソッドは親に置き、個別の動力やブレーキの違いは子で表現します。
親クラスと子クラスの関係
子クラスは親クラスのプロパティやメソッドを受け継ぎ、必要に応じて振る舞いを追加または上書きします。
子は親の一種であるという関係を守ると、設計が自然になります。
メソッドとプロパティの流れ
親にある機能は子でも使えますが、子で上書きして自分用に調整できます。
これにより、共通性と個別性の両立が可能になります。
is-aを意識した設計
継承は「AはBである(is-a)」関係に使います。
「AはBを持つ(has-a)」関係の場合は、別のクラスをプロパティとして持つ構成(コンポジション)が適しています。
is-aとhas-aの比較
| 観点 | is-a(継承) | has-a(コンポジション) |
|---|---|---|
| 関係 | AはBである | AはBを持つ |
| 例 | 車は乗り物である | 車はエンジンを持つ |
| 向き不向き | 型として同列に扱いたい | 部品の入れ替えや差し替えが多い |
迷ったらまずhas-aを検討し、is-aが明らかなときだけ継承を選ぶと安全です。
共通の処理を親にまとめる
複数のクラスに同じ処理があるなら、親クラスに集約して重複をなくします。
共通化すると修正が1回で済み、挙動の一貫性も維持できます。
抽象メソッドという考え方
親で「呼び出しは定めるが中身は子が決める」穴を空けておく方法があります。
これにより、流れは共通・中身は各自という柔軟さが得られます。
継承のやりすぎに注意
継承階層が深くなると、どこで何が定義されているのか把握が難しくなります。
変更の影響範囲が読みにくくなり、学習コストも跳ね上がります。
代わりに考えること: コンポジション
部品を組み合わせる発想なら、必要な機能だけ差し替えられます。
入れ替えやすさが求められる場面では継承より有利です。
多態性の基本
多態性とは何か
多態性(ポリモーフィズム)は、同じ操作でも対象に応じて振る舞いが変わる性質です。
共通の型で扱いながら、中身に合わせた正しい処理が自動で選ばれます。
例: draw()の呼び分け
図形の共通操作draw()を呼ぶと、丸なら円を、四角なら四角形を描きます。
呼び出し側は「描く」という意図だけ伝え、詳細は各図形に任せます。
メソッドのオーバーライドで振る舞いを変える
親で決めたメソッドを子が上書き(オーバーライド)し、具体的な挙動を実装します。
同じ名前のメソッドでも、実体に応じて適切な中身が実行されます。
注意: メソッドのシグネチャ
オーバーライドは、親と同じ名前と引数(シグネチャ)で中身だけ変えるものです。
名前だけ同じで引数が違う場合は別機能として扱われる点に注意してください。
共通の型でまとめて扱う
親型やインターフェースのコレクションに、さまざまな子オブジェクトを混在させられます。
呼び出し側は共通の型だけを意識し、個別の分岐を大量に書かなくて済みます。
実際の恩恵: if分岐が減る
種類ごとに条件分岐を並べる代わりに、同じメソッドを呼ぶだけで済みます。
読みやすさも保守性も大きく向上します。
同じメソッド名で違う結果を得る
同名メソッドで結果が変わる理由は2つあります。
1つはオーバーライド(対象の違いで中身が変わる)、もう1つはオーバーロード(引数の違いで別の同名メソッドを呼ぶ)です。
使い分けの目安
対象が違うときはオーバーライド、処理の入口を増やしたいときはオーバーロードです。
初心者はまずオーバーライドを理解できれば、実務で困りにくくなります。
多態性のメリット
新しい種類を追加しても、既存の呼び出しコードを変えずに済むことが多いです。
拡張に強く、変更の影響を小さく抑えられるのが多態性の大きな価値です。
テストと再利用にも効く
共通の型でテストを書けば、子クラスを差し替えるだけで広く検証できます。
モックなどの置き換えもやりやすく、再利用性が高まります。
まとめ
本記事では、オブジェクト指向の3つの柱であるカプセル化、継承、多態性をやさしく解説しました。
カプセル化は安全な窓口で守る、継承は共通性をまとめる、多態性は同じ操作で違いを吸収するというイメージが持てれば第一歩は成功です。
次に学ぶときは、小さな題材(例: 図形や家電)を選び、まずクラスとオブジェクトを書き分けてみてください。
最小公開の原則を守り、is-aよりhas-aを優先し、共通の型で扱う習慣を意識すると、自然と変更に強いコードになります。
焦らず段階的に練習して、理解を確かなものにしていきましょう。
