【ITニュース解説】# Week 06 Task 02: Strategy and Adapter Patterns in JavaScript
2026年09月29日に「Dev.to」が公開したITニュース「# Week 06 Task 02: Strategy and Adapter Patterns in JavaScript」について初心者にもわかりやすく解説しています。
ITニュース概要
JavaScriptのデザインパターン「Strategy」と「Adapter」を紹介。Strategyは複数の処理方法を実行時に切り替え、コードを柔軟にする。Adapterは互換性のないシステム間を繋ぎ連携させる。これらにより、保守しやすく拡張性の高いコードが書けるようになる。
ITニュース解説
この解説は、JavaScriptにおける「Strategyパターン」と「Adapterパターン」という二つの重要なデザインパターンについて、システムエンジニアを目指す初心者にも理解できるように掘り下げるものだ。デザインパターンとは、ソフトウェア開発で繰り返し現れる問題に対する、実績のある解決策をまとめた「設計のテンプレート」のようなものだ。これらを学ぶことで、コードはより柔軟になり、再利用しやすくなり、将来の変更にも対応しやすくなる。つまり、保守性が高まるということだ。
まず、Strategyパターンから見ていこう。Strategyパターンは、「ある操作を実行する際に、複数の異なるやり方の中から、実行時に一つを選んで適用したい」という場面で非常に役立つ。もしStrategyパターンを使わなければ、多くの場合、一つの大きな処理の中に複数のif-else文やswitch文を使って、どの処理を実行するかを振り分けることになるだろう。しかし、これでは新しい処理方法が追加されるたびに、その大きな処理を修正しなければならず、コードが複雑になり、ミスも起きやすくなる。
Strategyパターンでは、それぞれの処理方法(「戦略」と呼ぶ)を独立したクラスとして定義する。例えば、オンラインショッピングのアプリケーションで割引を適用する場合を考えてみよう。割引には「割引なし」「パーセンテージ割引」「定額割引」といった複数の種類がある。Strategyパターンを使うと、これらの割引方法をそれぞれ異なる「戦略クラス」として作成するのだ。
具体的な実装を見ていこう。「割引なし」の戦略は、受け取った金額をそのまま返す簡単なクラスだ。NoDiscountというクラスがそれに当たる。次に「パーセンテージ割引」は、指定された割合(例えば10%)に基づいて金額を計算し、割引後の価格を返すPercentageDiscountクラスとなる。そして「定額割引」は、指定された固定の金額(例えば200円)を差し引くFlatDiscountクラスだ。このとき、割引後の価格が0を下回らないようにする配慮も忘れてはならない。
これらの割引戦略を実際に利用する「Checkout(チェックアウト)」クラスを作成する。このCheckoutクラスは、コンストラクターでどの割引戦略を使うかを指定できる。また、途中で割引戦略を変更することも可能だ。最終的な価格を計算する際には、Checkoutクラスは自身が持っている割引戦略のapplyメソッドを呼び出すだけだ。このようにすることで、Checkoutクラス自体は具体的な割引計算のロジックを知る必要がなくなり、非常にシンプルになる。新しい割引方法が追加されても、Checkoutクラスを変更する必要はなく、新しい割引戦略クラスを作成するだけで対応できるのだ。これがStrategyパターンの大きなメリットで、責任の分離、コードの拡張性向上、そしてテストの容易さにつながる。
次に、Adapterパターンについて説明する。Adapterパターンは、「互換性のない二つのインターフェース(システム間の接点や約束事)を、互いに連携できるようにする」ためのパターンだ。身近な例で言うと、海外旅行で使う変換プラグがこれに当たる。日本の電化製品のプラグ形状と、渡航先のコンセントの形状が異なるとき、変換プラグを使うことで、互いに異なる規格のものを接続し、電化製品を使えるようにする。ソフトウェアの世界でも、全く同じ考え方でこの問題を解決できる。
例えば、私たちのアプリケーションが「pay(amount)」というメソッドを持つ決済ゲートウェイ(支払いシステム)を期待しているとしよう。しかし、もし既存の古い決済システムが「makePayment(amountInCents)」というメソッドしか提供していなかったらどうだろうか。アプリケーションが期待する「金額をドル単位で受け取るpayメソッド」と、古いシステムが提供する「金額をセント単位で受け取るmakePaymentメソッド」では、インターフェースが異なっており、そのままでは連携できない。
ここでAdapterパターンの出番だ。古い決済システム自体や、アプリケーションの決済処理全体を変更するのではなく、その間に「PaymentAdapter」というアダプターを挟み込むのだ。このPaymentAdapterは、アプリケーションが期待する「pay(amount)」メソッドを提供しつつ、その内部で古い決済システムの「makePayment(amountInCents)」メソッドを呼び出す。このとき、アプリケーションから受け取ったドル単位の金額を、セント単位に変換して古いシステムに渡すという処理を行う。
つまり、アプリケーションはアダプターに対して「10ドル支払ってほしい」と要求すると、アダプターはそれを「1000セント支払ってほしい」と古い決済システムに伝える。古い決済システムは、自分が理解できる形式で処理を行い、結果を返す。このように、アダプターは異なるインターフェースを持つシステム間の翻訳者のような役割を果たす。これにより、既存のレガシーシステムを新しいシステムに簡単に統合できるようになり、コードの変更範囲を最小限に抑えることができる。
StrategyパターンとAdapterパターンはどちらもコードを整理するのに役立つが、解決する問題の性質は異なる。Strategyパターンは「同じ問題を解決するための異なるアルゴリズムや振る舞いを、実行時に選択する」ことに焦点を当てる。一方、Adapterパターンは「互換性のないインターフェースを持つ既存のシステム同士を、変更せずに連携させる」ことに焦点を当てる。
これらのパターンを実装する際には、その動作が意図通りであることを確認するためのテストを書くことが非常に重要だ。Node.jsに組み込まれているassertモジュールのようなツールを使って、割引計算が正しく行われるか、アダプターが正しく金額を変換して古い決済システムを呼び出すか、といった点を検証する。テストを書くことで、コードの品質と信頼性を高めることができる。
最終的に、Strategyパターンはアプリケーションの振る舞いやアルゴリズムの選択肢を柔軟にし、Adapterパターンは異なるシステム間の互換性問題を解決する。これら二つのデザインパターンを理解し、適切に使いこなせるようになれば、システムエンジニアとしてよりモジュール化され、柔軟で、将来にわたって保守しやすい大規模なアプリケーションを構築するのに非常に役立つだろう。