オブジェクト指向とは(Unity初心者向け)
2025/05/14
始めに
『override?多態性?カプセル化?何のために…』
初めてオブジェクト指向に触れたとき、そんな疑問を持ったことがある方も多いのではないでしょうか?
私はありました。
この記事では、「初心者でも感覚で分かるオブジェクト指向」をテーマに、
カプセル化・継承・多態性などの基本概念を、Unityでの開発向けにざっくり紹介します。
開発効率が上がる理由
[オブジェクト指向]とは平たく言うと[現実の物のように、プログラムの中でも物として扱う ]
というシステム開発における重要且つ基本的な考え方の1つです。
処理を部品化し、組み合わせる事によってコードを作る方法です。
以下の Scratch の例を見てみましょう。
Scratchでは処理を“部品”として組み合わせるスタイルが、オブジェクト指向と似ています。
オブジェクト指向の考え方により、
再利用性・拡張性が高まり、結果として開発効率も向上します。


(画像: Scratchのブロック)
オブジェクト指向の[4つの柱]
オブジェクト指向プログラミング(OOP)では、以下の4つが基本的な考え方とされています:
- カプセル化
- 多態性(ポリモーフィズム)
- 継承
- 抽象化
以下から、各柱について具体的なコード例とともに解説します。
カプセル化とは
平たく言うと「データを壁で守り、必要な出入り口を作る仕組み」です。
もし変数を誰でも何処でも読み書きができてしまったら、
原因不明のバグが発生しやすくなり、修正が難しくなってしまいます。
以下のコード例のように、
BadSampleでは Valueを直接読み書きが可能ですが、
GoodSampleでは_valueはprivateに守られており
外部からは読み取り専用のプロパティ GetValueを通じてアクセスします。
これにより、勝手な書き換えを防ぎ、安全なコード設計ができます。
BadSample:データがむき出し
// カプセル化していない
public class BadSample
{
// 外部から直接読み書きできる
public int Value = 0;
}
GoodSample:中を隠して安全に
// カプセル化してある
public class GoodSample
{
// クラス内部のみで読み書きできる
private int _value = 0;
// プロパティを通じて読み取りのみ可能
public int GetValue { get => _value; }
// 初期値を代入
public GoodSample(int value)
{
_value = value;
}
}
長所
- データの保護
- バグの原因究明しやすくなる
- 変更に強くなる
注意点
- 手間が増える
- 設計力が必要
つまりカプセル化は、安全で保守しやすいコードを書くために欠かせません!
多態性(ポリモーフィズム)とは(virtual / override)
平たく言うと「同じ関数名で、中身の処理だけを切り替える仕組み」です。
以下のコード例のように、
BadSampleは動物ごとに鳴く関数名Bark()やMeow()等がバラバラですが、
GoodSampleは鳴く関数名がSpeak()に統一されており、
Animal型の変数にDogやCatを代入しても、それぞれの処理が呼び出されます。
-
BadSample:統一されてない関数名
//関数名統一していない // 犬クラス(鳴く関数名はBark) public class Dog { public void Bark() { Debug.Log("ワン"); } } // 猫クラス(鳴く関数名はMeow) public class Cat { public void Meow() { Debug.Log("ニャー"); } } // 動物ごとに個別で扱う必要があり、共通処理がしづらい // 新しい動物を追加するたびに条件分岐が必要になる -
GoodSample:統一された関数名
// 多態性を活用している。 // 動物の共通クラス public class Animal { // 派生クラスで上書きできる仮想関数(virtual) public virtual void Speak() { } } // 犬クラス(Animal を継承) public class Dog : Animal { // Speak メソッドを上書き(override) public override void Speak() { Debug.Log("ワン"); } } // 猫クラス(Animal を継承) public class Cat : Animal { // Speak メソッドを上書き(override) public override void Speak() { Debug.Log("ニャー"); } } -
Animal型でDogやCatを代入
public void AddSpeak { List<Animal> animals = new List<Animal> { new Dog(), new Cat() }; // すべてAnimal型として扱いながら、それぞれのSpeakが呼ばれる foreach (var animal in animals) { animal.Speak(); // 実行時に Dog か Cat の中身に応じて切り替わる } }
長所
- 可読性・保守性の向上
- コードの再利用性向上
- 柔軟な設計ができる
注意点
- 処理の追跡が難しくなる
- 誤用による設計の混乱
つまり多態性(ポリモーフィズム)は、
「同じインターフェースで異なる処理を実行する」柔軟な設計を可能にします。
継承とは
平たく言うと「親を基に子を作る遺伝」のようなものです。
複数のクラスに共通する処理を「親クラス」にまとめることで、重複をなくし、メンテナンス性を高めることができます。
Unityを使っている人ならよく見る MonoBehaviour も、この「継承」の仕組みを使っています。
以下のコード例では、Sample クラスが MonoBehaviour を継承しているため、Unityが自動的に Start() や Update() を呼び出してくれるようになります。
MonoBehaviourの例
using UnityEngine;
public class Sample : MonoBehaviour
{
private void Start() { }
private void Update() { }
}
そして継承の例として、以下のコード例のように、
BadSample では犬・猫・人のそれぞれに同じ Walk() と Dash() の処理を個別に書いていますが、
GoodSample では、共通の Animal クラスに Walk() と Dash() をまとめて書き、
各クラスがそれを 継承することで、重複するコードを書かずに実装できます。
-
BadSample:重複があるコード
// 再利用がなく、コードの重複がある悪い例(BadSample) // 犬クラス public class Dog { public void Walk() { } public void Dash() { } } // 猫クラス public class Cat { public void Walk() { } public void Dash() { } } // 人間クラス public class Human { public void Walk() { } public void Dash() { } } -
GoodSample:再利用性が高いコード
// 継承を使って重複を避け、再利用性を高めた良い例(GoodSample) // 共通の動物クラス(Animal) public class Animal { // 歩く動作(共通) public void Walk() { } // ダッシュする動作(共通) public void Dash() { } } // 犬クラス(Animal を継承) public class Dog : Animal { // 特別な処理があればここに追加できる } // 猫クラス(Animal を継承) public class Cat : Animal { // 特別な処理があればここに追加できる } // 人間クラス(Animal を継承) public class Human : Animal { // 特別な処理があればここに追加できる }
長所
- コードの再利用性が高い
- 保守性が上がる
- 一貫性のある設計ができる
- 多態性(ポリモーフィズム)と組み合わせやすい
注意点
- 親クラスに依存しすぎると柔軟性が落ちる
- 設計が硬直化しやすい
- classの多重継承が使えない(C#では)
- 変更の影響範囲が大きい
つまり継承は共通する処理の重複を減らし、保守性や再利用性を高める仕組みです。
さらに、多態性(ポリモーフィズム)との組み合わせによって、柔軟で拡張性のある設計が可能になります。
抽象化とは(abstract / interface)
平たく言うと「複数のクラスに共通する処理や性質(例:ダメージを受ける、回復するなど)だけを取り出してまとめる」ものです。
その手段として、abstract や interface を使うことがあります。
例えるなら、「自動販売機のボタン」だけが見えていて、中の機械や配線がどうなっているかは知らなくてもいい、という状態です。
抽象化を用いることで、使い方と中身を分けられるので、バグを減らすことができ、拡張がしやすくなります。
以下のコード例のように、
BadSampleでは、Player と Enemy の両方に同じような AddDamage() や AddCure() 関数が個別に定義されています。
これでは、処理の重複が増え、メンテナンスが難しくなってしまいます。
一方、GoodSampleでは「ダメージを受ける」「回復する」といった共通の振る舞いを
abstract class や interface として抽出し、それを継承・実装することで重複を避けています。
BadSample:重複があるコード
public class Player
{
public void AddDamage(int value) { }
public void AddCure(int value) { }
}
public class Enemy
{
public void AddDamage(int value) { }
public void AddCure(int value) { }
}
abstractでの良い例
以下のコード例のように、共通機能は親クラスである Entityクラスにまとめ、
個別の処理は子クラスに任せることで、変更に強い設計になります。
これにより、共通の処理を統一して管理できるため、バグ修正や機能追加が1箇所で済み、メンテナンス性が向上します。
-
GoodSample_abstract:共通点が分かりやすい
public abstract class Entity { public abstract void AddDamage(int value); public abstract void AddCure(int value); } public class Player : Entity { public override void AddDamage(int value) { } public override void AddCure(int value) { } } public class Enemy : Entity { public override void AddDamage(int value) { } public override void AddCure(int value) { } }
interfaceでの良い例
interface は「複数の役割を持たせたいとき」や「柔軟に設計したいとき」に便利です。
abstract classと異なり、多重実装が可能なため、設計の幅が広がります。
interfaceは複数の機能を持てるので、例えば『攻撃できる』と『回復できる』を別々に実装することができます。
-
GoodSample_interface:機能の付け外しがしやすい
// Player はダメージも回復もできるが、Enemy はダメージしか受けない、という設計 public interface IDamageable { void AddDamage(int value); } public interface ICurable { void AddCure(int value); } public class Player : IDamageable, ICurable { public void AddDamage(int value) { } public void AddCure(int value) { } } public class Enemy : IDamageable { public void AddDamage(int value) { } }
特徴をまとめますと、
| 特徴 | abstract class | interface |
|---|---|---|
| 継承数 | 1つまで | 複数OK |
| 用途 | 「共通の基本機能」がある時 | 「役割」や「能力」を付与したい時 |
長所
- 設計の共通化・整理
- 拡張や変更がしやすくなる
- 役割分担が明確になる
- 保守性の向上
注意点
- 設計が複雑になることがある
- 初心者には理解しづらい
- 処理の追跡が難しいことがある
つまり抽象化は
「共通する本質的な性質だけを取り出して整理し、使いやすく・変更しやすい設計を可能にする考え方」です。
オブジェクト指向の長所
- 再利用性
既存のクラスを使い回せる - 保守性
修正箇所が限定される - 拡張性
新しい機能追加が容易
オブジェクト指向の注意点
- 長い設計時間
構造を考える技術と時間がかかる。 - 変更に弱い設計
1つの変更が他にも影響を与える。
最後に
オブジェクト指向は最初こそ難しく感じるかもしれませんが、
「共通点をまとめる」「中身を隠す」「同じ形で振る舞いを変える」といった考え方を意識すれば、少しずつ理解できるようになります。
この記事で紹介したカプセル化・継承・多態性・抽象化は、コードを見やすく・直しやすく・拡張しやすくするための大切な基礎です。
ぜひ、実際のコードの中で使ってみて、感覚をつかんでいってください。
Discussion