mediator-pattern について
JavaScript のメディエーターパターンとミドルウェアチェーンを解説する学習スキルです。チャットルームと Express.js の例を通じて、中央の調整役がコンポーネント間の通信を仲介する方法を示します。
主な機能
- 01メディエーター経由のリクエスト転送
- 02コンポーネント間の直接依存の削減
- 03ミドルウェア関数の連結
- 04リクエストとレスポンスの変更
活用シーン
- 01チャットルーム内のメッセージ調整
- 02Express.js ミドルウェアによるリクエスト処理
- 03多数のコンポーネント間通信の簡素化
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ patternsdev/ skills --skill mediator-patternインストール後、Claude Code で/mediator-patternを入力して読み込まれたか確認します。
詳細
メディエーター/ミドルウェアパターン
メディエーターパターンを使うと、コンポーネントは中心となるメディエーターを介して相互にやり取りできるようになります。互いに直接やり取りするのではなく、メディエーターがリクエストを受け取り、転送します。JavaScriptでは、メディエーターは多くの場合、オブジェクトリテラルや関数にすぎません。
このパターンは、航空管制官とパイロットの関係にたとえることができます。パイロット同士が直接やり取りするのではなく、航空管制官と連絡を取ります。航空管制官は、飛行機同士が衝突することなく安全に飛行できるよう、すべての飛行機に必要な情報が行き渡るようにします。
使用する場面
- 複数のオブジェクトが通信する必要があり、直接の多対多関係では混乱が生じる場合に使用します
- ミドルウェアチェーン(例:Express.jsのミドルウェア)を実装する際に役立ちます
使用しない場面
- 2つのコンポーネント間の直接通信のほうがシンプルで、システムの参加者が少ない場合
- メディエーター自体が、保守しにくいモノリシックな「神オブジェクト」になってしまう場合
- 中央の調整役を設けなくても、イベント駆動パターン(オブザーバー/パブサブ)で十分に疎結合を実現できる場合
手順
- リクエストを処理し、適切なハンドラーに転送する中央メディエーターを作成します
- ミドルウェアパターンを使用して、リクエスト/レスポンスを変更できる処理関数を連結します
- 各コンポーネントが互いを認識しないようにします。各コンポーネントが認識するのはメディエーターだけです
詳細
JavaScriptで飛行機を操縦することはないと思いますが、オブジェクト間の多方向のデータを扱うことはよくあります。コンポーネントの数が多い場合、コンポーネント間の通信はかなり複雑になる可能性があります。
すべてのオブジェクトがほかのオブジェクトと直接やり取りする多対多関係にするのではなく、オブジェクトのリクエストをメディエーターが処理します。メディエーターはリクエストを処理し、必要な場所に転送します。
メディエーターパターンの適切なユースケースは、チャットルームです。チャットルームのユーザー同士が直接やり取りすることはありません。代わりに、チャットルームがユーザー間のメディエーターとして機能します。
class ChatRoom {
logMessage(user, message) {
const time = new Date();
const sender = user.getName();
console.log(`${time} [${sender}]: ${message}`);
}
}
class User {
constructor(name, chatroom) {
this.name = name;
this.chatroom = chatroom;
}
getName() {
return this.name;
}
send(message) {
this.chatroom.logMessage(this, message);
}
}
チャットルームに接続されたユーザーを新しく作成できます。各ユーザーのインスタンスには、メッセージの送信に使えるsendメソッドがあります。
ケーススタディ
Express.jsは、人気のあるウェブアプリケーションサーバーフレームワークです。ユーザーがアクセスできる特定のルートにコールバックを追加できます。
ユーザーがルート'/'にアクセスしたときに、リクエストにヘッダーを追加するとします。このヘッダーはミドルウェアのコールバックで追加できます。
const app = require("express")();
app.use("/", (req, res, next) => {
req.headers["test-header"] = 1234;
next();
});
nextメソッドは、リクエストとレスポンスのサイクルにおける次のコールバックを呼び出します。これにより、リクエストとレスポンスの間、またはその逆に、ミドルウェア関数のチェーンを効果的に作成できます。
test-headerが正しく追加されたかどうかを確認する別のミドルウェア関数を追加しましょう。前のミドルウェア関数による変更は、チェーン全体で参照できます。
const app = require("express")();
app.use(
"/",
(req, res, next) => {
req.headers["test-header"] = 1234;
next();
},
(req, res, next) => {
console.log(`Request has test header: ${!!req.headers["test-header"]}`);
next();
}
);
完璧です。1つまたは複数のミドルウェア関数を通じて、レスポンスに至るまでリクエストオブジェクトを追跡し、変更できます。
ユーザーがルートエンドポイント'/'にアクセスするたびに、2つのミドルウェアコールバックが呼び出されます。
ミドルウェアパターンを使うと、すべての通信を1つの中心点に集約することで、オブジェクト間の多対多関係を簡単にシンプル化できます。