コンポジション
オブジェクトを組み合わせて機能を構築する設計手法で、継承よりも柔軟性が高い
設計オブジェクト指向
コンポジションとは
コンポジション (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 でのコンポジションのコード例を示す。
// ❌ 継承ベース (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 を組み合わせるのはコンポジションの実践。
実践的な知識は関連書籍でも得られる。
この記事は役に立ちましたか?
関連用語
関連する記事
OS・低レイヤー本ガイド - コンピュータの仕組みを学ぶ技術書の選び方
OS、コンパイラ、ネットワークなど低レイヤーを学べる技術書の 4 ジャンルと、どこから始めるべきかの指針、賞味期限の見極め方を紹介します。
README を書くように本を読む - エンジニアのための構造化読書法
エンジニアが日常的に書く README のフォーマットを読書に応用する方法を紹介します。目的・使い方・注意点の 3 点で本の内容を整理すると、知識の再利用性が飛躍的に高まります。
セキュリティ本ガイド - Web 開発者が読むべき技術書の選び方
Web セキュリティの基礎から実践まで学べる技術書の選び方マトリクスと、読了後にやるべき 3 つのアクションを紹介します。