「Strategyパターン」の説明で挫折してしまった方へ。OCPとポリモーフィズムを「役割」の視点で解説します

システム設計

プログラミングの設計を学ぼうとして、このような解説に遭遇したことはないでしょうか。

  • 「Strategyパターンは、アルゴリズムをカプセル化して切り替えるためのものです」
  • 「OCP(開放閉鎖原則)とは、拡張に対して開いており、修正に対して閉じていることを指します」

…実のところ、これだけを読んで「明日からの実装に活かせる」と感じる方は、決して多くないはずです。


なぜ、これまでの解説は難しく感じられたのでしょうか

それには明確な理由があると考えています。

  1. 「何(What)」の説明が中心で、「誰が(Who)」という役割の説明が不足している。
  2. 「仕組み」は語られていても、現場での「運用のしやすさ」に結びついていない。
  3. 「専門用語」という言葉の壁が、理解を妨げるノイズになっている。

本記事では、これまでの抽象的なアプローチとは一線を画します。
専門用語を一度脇に置き、「役割」と「責任の委任」という視点だけで、設計を捉え直してみたいと思います。


結論:設計とは「判断の責務を適切に分散させること」

OCPやポリモーフィズムの本質は、決して複雑なものではありません。私たちが目指すべきことは、極めてシンプルです。

「自分ですべてを判断しようとせず、適切な担当者に任せる仕組みを作ること」

  • OCP:自分(店長)は業務の流れ(台本)を書き換えない。新しい業務が増えた際は、新しい担当者に「自分の仕事」を完結させるよう依頼する。
  • ポリモーフィズム:依頼を受けた担当者たちが、それぞれの専門性に基づいて自律的に動く。

この関係性が構築できれば、複雑な if 文や switch 文をコードから排除することが可能になります。


レストランの店長の視点で考える「責務の委任」

皆様がレストランの店長であると想像してみてください。
ここでは、システムの根幹となる「支払い処理」の設計を例に挙げます。


【課題の多い設計】店長がすべての判断を抱え込む(OCP違反)

// 店長が「誰が何をするか」をすべて把握し、その都度判断を下している状態
function pay(type) {
    if (type === 'credit') {
        // Aさんの連絡先を確認し、個別に指示を出す
    } else if (type === 'paypay') {
        // Bさんの連絡先を確認し、個別に指示を出す
    } else if (type === 'apple_pay') {
        // Cさんの連絡先を確認し、個別に指示を出す
    }
}

この設計における問題点:
新しい支払い方法が追加されるたびに、店長(メインの処理フロー)が毎回判断ロジックを書き換え、再テストを行わなければなりません。

これでは、規模が拡大するにつれて店長の負担は増大し、修正によるミスが発生するリスクも高まってしまいます。


【理想的な設計】「受付係」に判断を委ねる(OCP準拠)

店長は、次のように振る舞いを変えてみます。

「受付係(Registry)さん、お客様が選択された方法に応じて、適切な担当者(Processor)を呼んでください。あとの実務は、その方にお任せします」

// 店長は「誰が実務を行うか」の詳細を知る必要はありません。
function pay(type) {
    const processor = registry.get(type); // 受付係に担当者の選定を依頼する
    processor.execute();                  // 担当者がそれぞれの専門知識で動く(ポリモーフィズム)
}

店長はこの処理フローを二度と修正する必要がありません。
新しい支払い方法が増えたとしても、店長は現在の業務を変えることなく、平穏を保つことができるのです。


専門用語を「現場の役割」に置き換えて理解する

現場でスムーズに活用できるよう、カタカナ語を「役割名」に変換してみましょう。

専門用語現場での役割役割の詳細
Strategy業務の手順書「カード決済」「QR決済」といった、個別のマニュアルです。
Processor現場の担当者手順書を理解し、実務を遂行する人です。「1人1手順書」が原則です。
Provider提携先の企業決済を代行する「Stripe社」等の外部機関です。担当者の連絡先となります。
Channelお客様の選択肢画面上に表示される「支払い手段」です。これが増えると担当者も増えます。
Payload担当者専用の備品担当者ごとに必要な情報(トークン等)を収める器です。他者とは共有しません。
Registry振り分けの受付係「この手段なら、担当者はあの方だ」と判断する人です。判断の責任をここに集約します。
Polymorphism指示の共通化「誰に対しても『お願いします』の一言で実務が始まる」便利な仕組みです。
OCPフローの固定化「メインの処理の流れは変えず、担当者の追加だけで対応する」という方針です。

この設計がもたらす「真のメリット」とは

「拡張性」や「保守性」という抽象的な言葉を超えて、開発現場にどのような恩恵をもたらすのかを整理します。

  1. 「既存機能を壊す」リスクの低減
    メインの処理フロー(店長の動き)を一切変更せずに機能を追加できるため、意図しないバグ(デグレード)の発生を物理的に防げます。
  2. テスト効率の大幅な向上
    新機能を追加する際は、新しい担当者のコードだけをテストすれば済みます。既存の安定したコードまでテストし直す必要はありません。
  3. レビューコストの削減
    レビュアーは「新しく追加された担当者のコード」だけに集中できます。システム全体の整合性を一から確認する手間が省けます。

まとめ:これだけ答えられれば合格です

もし後輩から「なぜ、これほどまでに if 文を避ける必要があるのですか?」と尋ねられたら、ぜひこう答えてあげてください。

if 文を増やすということは、その都度『全体の流れ』を書き換えるというリスクを負うことになります。 誰が実務を担うかは『受付係』にお任せして、店長は『お客様にサービスを提供する』という本来の目的だけに集中すべきではないでしょうか」


関連記事のご案内

本記事の内容をより具体的に理解したい方は、以下の記事もあわせてご覧ください。


専門用語という言葉に惑わされないでください。 大切なのは、「誰がどの判断に責任を持っているか」を見極めることなのです。

コメント

タイトルとURLをコピーしました