コンポジション

オブジェクトを組み合わせて機能を構築する設計手法で、継承よりも柔軟性が高い

設計オブジェクト指向

コンポジションとは

コンポジション (Composition) は、オブジェクトを組み合わせて機能を構築する設計手法である。「継承よりコンポジションを優先せよ」(Favor composition over inheritance) は GoF デザインパターンの基本原則。

継承 vs コンポジション

観点 継承 コンポジション
関係 is-a (犬は動物) has-a (車はエンジンを持つ)
結合度 高い (親の変更が子に波及) 低い (部品を差し替え可能)
柔軟性 低い (単一継承の制約) 高い (複数の部品を組み合わせ)
テスト 親クラスに依存 部品を個別にテスト可能

継承の問題

// ❌ 継承: ダイヤモンド問題、脆い基底クラス
class Animal { move() {} }
class Bird extends Animal { fly() {} }
class Penguin extends Bird { fly() { throw new Error('飛べない'); } }
// Penguin は Bird だが fly() できない → リスコフの置換原則に違反

コンポジションで解決

// ✅ コンポジション: 機能を部品として組み合わせ
type Movable = { move: () => void };
type Swimmable = { swim: () => void };

const createPenguin = (): Movable & Swimmable => ({
  move: () => console.log('歩く'),
  swim: () => console.log('泳ぐ'),
});
// fly を持たない → 型レベルで安全

React でのコンポジション

// ❌ 継承ベース (React では非推奨)
class SpecialButton extends Button { ... }

// ✅ コンポジション: children, render props, hooks
function Card({ children }: { children: React.ReactNode }) {
  return <div className="card">{children}</div>;
}

<Card>
  <h2>タイトル</h2>
  <p>本文</p>
</Card>

関数コンポジション

const double = (x: number) => x * 2;
const addOne = (x: number) => x + 1;

// 関数を合成
const doubleThenAddOne = (x: number) => addOne(double(x));
doubleThenAddOne(3); // 7

// pipe で読みやすく
const pipe = (...fns: Function[]) => (x: any) =>
  fns.reduce((v, f) => f(v), x);
const transform = pipe(double, addOne);

Step Functions で小さな Lambda を組み合わせるのはコンポジションの実践。

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

関連用語