タイトル: オブジェクト指向の概念
SEOタイトル: オブジェクト指向プログラミング (OOP) 完全ガイド
| この記事の要点 |
- OOP の三大原則: カプセル化 / 継承 / ポリモーフィズム(+ 抽象化を加え四大原則とも)
- クラス = 設計図、オブジェクト = 設計図から作った実体 (インスタンス)
- SOLID 原則: 単一責任 / 開放閉鎖 / Liskov / インタフェース分離 / 依存性逆転
- デザインパターン: Singleton / Factory / Observer / Strategy / Decorator など 23 種類が GoF で有名
- 関数型 (FP) との対比: OOP は状態 + 振る舞いをカプセル化、FP は純粋関数 + 不変データ
|
OOP とは何か
オブジェクト指向プログラミング (Object-Oriented Programming, OOP) は、データ(状態)と振る舞い(メソッド)をオブジェクトという単位でまとめて扱うパラダイムです。1960 年代の Simula、1970 年代の Smalltalk が祖。現代では Java / C++ / C# / Python / Ruby / PHP / Kotlin / Swift など多くの言語が採用。
三大原則 (+ 抽象化で四大原則)
| 原則 | 意味 | キーワード |
| カプセル化 (Encapsulation) | データを隠蔽し、操作はメソッド経由 | private, getter/setter |
| 継承 (Inheritance) | 親の機能を子に引き継ぐ | extends, super |
| ポリモーフィズム (Polymorphism) | 同じインタフェースで異なる振る舞い | override, interface |
| 抽象化 (Abstraction) | 本質的な特徴だけを抽出 | abstract, interface |
クラスとオブジェクト
// クラス = 設計図
public class Car {
// フィールド(属性 / 状態)
private String color;
private int speed;
// コンストラクタ
public Car(String color) {
this.color = color;
this.speed = 0;
}
// メソッド(振る舞い)
public void accelerate(int delta) {
this.speed += delta;
}
public int getSpeed() {
return speed;
}
}
// オブジェクト = 設計図から作った実体
Car redCar = new Car("red"); // インスタンス化
Car blueCar = new Car("blue");
redCar.accelerate(50);
System.out.println(redCar.getSpeed()); // 50
System.out.println(blueCar.getSpeed()); // 0 ← 別個の状態
カプセル化の実例
public class BankAccount {
private long balance; // ★ private で外部から直接触れない
public BankAccount(long initial) {
if (initial < 0) throw new IllegalArgumentException();
this.balance = initial;
}
public void deposit(long amount) {
if (amount <= 0) throw new IllegalArgumentException();
balance += amount;
}
public void withdraw(long amount) {
if (amount > balance) throw new IllegalStateException("残高不足");
balance -= amount;
}
public long getBalance() { return balance; }
}
// ❌ 直接書換できない(コンパイルエラー)
// account.balance = -1000000;
// ✅ メソッド経由で必ずバリデーション通る
account.withdraw(500);
ポリモーフィズム (多態性)
// 共通の interface
interface Shape {
double area();
}
class Circle implements Shape {
private double r;
public Circle(double r) { this.r = r; }
@Override
public double area() { return Math.PI * r * r; }
}
class Rectangle implements Shape {
private double w, h;
public Rectangle(double w, double h) { this.w = w; this.h = h; }
@Override
public double area() { return w * h; }
}
// 利用側は Shape インタフェースだけ知っていればよい
Shape[] shapes = { new Circle(3), new Rectangle(2, 4) };
for (Shape s : shapes) {
System.out.println(s.area()); // 実体に応じた計算
}
SOLID 原則
| 原則 | 名前 | 要点 |
| S | Single Responsibility | クラスの責務は 1 つ。変更理由が 1 つに |
| O | Open/Closed | 拡張に開き、変更に閉じる |
| L | Liskov Substitution | 子は親と置換可能 |
| I | Interface Segregation | 1 つの大インタフェースより小さな複数 |
| D | Dependency Inversion | 具象でなく抽象に依存 |
主要デザインパターン (GoF 23 種から抜粋)
| パターン | 分類 | 用途 |
| Singleton | 生成 | クラスのインスタンスをただ 1 つに(DBconnection 等) |
| Factory Method | 生成 | 生成処理を子クラスに委譲 |
| Abstract Factory | 生成 | 関連オブジェクト群をまとめて生成 |
| Builder | 生成 | 複雑なオブジェクトを段階的に構築 |
| Observer | 振る舞い | 状態変化を購読者に通知(イベント駆動) |
| Strategy | 振る舞い | アルゴリズムを差し替え可能に |
| Decorator | 構造 | 既存オブジェクトに動的に機能追加 |
| Adapter | 構造 | 異なる API を適合させる |
| Facade | 構造 | 複雑なサブシステムへの簡略 API |
Singleton の実装例
public class DbConnection {
private static DbConnection instance;
private DbConnection() { /* 接続初期化 */ }
public static synchronized DbConnection getInstance() {
if (instance == null) {
instance = new DbConnection();
}
return instance;
}
}
// 利用
DbConnection conn = DbConnection.getInstance();
Strategy の例
from abc import ABC, abstractmethod
class SortStrategy(ABC):
@abstractmethod
def sort(self, data): ...
class QuickSort(SortStrategy):
def sort(self, data):
# ... quicksort 実装
return sorted(data)
class MergeSort(SortStrategy):
def sort(self, data):
# ... mergesort 実装
return sorted(data)
class Sorter:
def __init__(self, strategy: SortStrategy):
self.strategy = strategy
def execute(self, data):
return self.strategy.sort(data)
# アルゴリズムを実行時に差し替え
sorter = Sorter(QuickSort())
print(sorter.execute([3,1,2]))
言語別の OOP 機能比較
| 機能 | Java | Python | C# | PHP |
| クラス定義 | class | class | class | class |
| 継承 | extends | (Parent) | : | extends |
| 多重継承 | × | ○ | × | × (trait あり) |
| interface | ○ | ABC で代替 | ○ | ○ |
| 抽象クラス | abstract | ABC | abstract | abstract |
| final | ○ | × | sealed | final |
| generics | ○ | typing.Generic | ○ | (8.0+ 弱) |
OOP と関数型 (FP) の対比
| 観点 | OOP | FP |
| 中心概念 | オブジェクト(状態+振る舞い) | 純粋関数 + 不変データ |
| 状態 | カプセル化された可変状態 | イミュータブル |
| 制御 | メッセージパッシング / 命令型 | 関数合成 / 宣言的 |
| 再利用 | 継承 / Composition | 高階関数 / カリー化 |
| 並行性 | ロックが必要 | 不変なので安全 |
| 代表言語 | Java, C#, C++ | Haskell, Erlang, F# |
| マルチパラダイム | Scala / Kotlin / Python / JS は両方サポート |
現代の OOP 設計指針
- Composition Over Inheritance: 継承より委譲を優先
- Tell Don't Ask: 状態を尋ねるな、命じよ(カプセル化徹底)
- Law of Demeter:
a.b.c.d のような連鎖アクセスを避ける
- イミュータブルファースト: 状態を持たせない設計を優先(Java の record / Kotlin の data class)
- ドメイン駆動設計 (DDD): ビジネス概念をクラスに直接マップ
- クリーンアーキテクチャ: 依存方向を内側(ドメイン)に向ける
FAQ
Q: 「オブジェクト指向は終わった」と聞きました
A: 一部の極端な意見。実際はOOP + FP のハイブリッドが主流。Java / Kotlin / Scala に Stream / map / filter のような FP 要素が入り、Haskell には型クラスがある。両者の長所を組み合わせて使うのが現代です。
Q: クラスを使わない OOP は?
A: JavaScript の prototype ベース、Go の構造体 + メソッド + interface など。クラスは OOP の一実装に過ぎません。
Q: SOLID は今でも有効?
A: 概念は今も有効ですが、マイクロサービスや関数型では別の指針(純粋性、単方向データフロー)も重要。原理主義は避けてバランスを。