ポリモーフィズム

同じインターフェースで異なる型のオブジェクトを扱い、実行時に適切な処理を選択する仕組み

オブジェクト指向設計

ポリモーフィズムとは

ポリモーフィズム (多態性) は、同じインターフェースで異なる型のオブジェクトを扱い、実行時に適切な処理を選択する仕組みである。「何をするか」を統一し、「どうするか」を型ごとに変える。

ポリモーフィズムの種類

種類 説明
サブタイプ インターフェースを実装 Notification を実装する Email, Slack
パラメトリック ジェネリクス Array<T>, Promise<T>
アドホック 関数オーバーロード 同名関数で異なる引数

TypeScript でのサブタイプポリモーフィズム

interface Notification {
  send(message: string): Promise<void>;
}

class EmailNotification implements Notification {
  async send(message: string) { await ses.send(message); }
}

class SlackNotification implements Notification {
  async send(message: string) { await slack.post(message); }
}

// 呼び出し側は具体的な型を知らない
async function notify(notifier: Notification, message: string) {
  await notifier.send(message); // 実行時に適切な send() が呼ばれる
}

await notify(new EmailNotification(), 'Hello');
await notify(new SlackNotification(), 'Hello');

Discriminated Union (TypeScript 的ポリモーフィズム)

type Shape =
  | { kind: 'circle'; radius: number }
  | { kind: 'rectangle'; width: number; height: number };

function area(shape: Shape): number {
  switch (shape.kind) {
    case 'circle': return Math.PI * shape.radius ** 2;
    case 'rectangle': return shape.width * shape.height;
  }
}
// TypeScript が網羅性をチェック

ポリモーフィズム vs if-else

// ❌ if-else: 新しい型を追加するたびに分岐を追加
function process(type: string) {
  if (type === 'email') { /* ... */ }
  else if (type === 'slack') { /* ... */ }
  else if (type === 'sms') { /* ... */ } // 追加
}

// ✅ ポリモーフィズム: 新しい型を追加するだけ
class SmsNotification implements Notification {
  async send(message: string) { /* ... */ }
}
// 既存のコードを変更せずに拡張 (開放閉鎖原則)

ポリモーフィズムのメリット

ポリモーフィズムにより、既存コードを変更せずに新しい型を追加できる (開放閉鎖原則)。テスト時にはモックに差し替えが容易で、条件分岐が型ごとのメソッドに分散されるためコードの可読性も向上する。

実践的な知識は関連書籍でも得られる。

関連用語