
オブジェクト同士の直接的な依存関係を減らすためのデザインパターンの、Mediator(メディエータ)について解説します。
Mediatorパターンは、「仲介者パターン」と言われ、
多数のオブジェクト同士の通信を、仲介役(Mediator)を通して行うことで、
オブジェクト間の依存関係を緩くするパターンです。
つまり、
「AがBを呼んで、BがCを呼んで…」という複雑なスパゲッティ依存を、「全部メディエータに任せる」形に整理するのが特徴です。
オブジェクト同士を直接つなげずに、中央の“仲介者”を通してやり取りさせるにはどうすればいいか、サンプルコードを見て理解しましょう。
構造イメージ
| 役割 |
説明 |
| Mediator(仲介者) |
全体の調整を担当。各コンポーネント間のやり取りを仲介する。 |
| ConcreteMediator |
実際にやり取りのルールを実装する。 |
| Colleague(同僚) |
Mediator経由で通信する各オブジェクト。 |
| ConcreteColleague |
実際のUIやコンポーネントなど。 |
サンプルコード1
チャットルーム(ユーザー間の通信)
Mediator(仲介者)
class ChatRoom {
showMessage(user, message) {
const time = new Date().toLocaleTimeString();
console.log(`[${time}] ${user.name}: ${message}`);
}
}
Colleague(参加者)
class User {
constructor(name, chatroom) {
this.name = name;
this.chatroom = chatroom;
}
send(message) {
this.chatroom.showMessage(this, message);
}
}
実行例(Client)
const chatroom = new ChatRoom();
const alice = new User("Alice", chatroom);
const bob = new User("Bob", chatroom);
alice.send("こんにちは、ボブ!");
bob.send("やあ、アリス!");
出力例
[10:15:12] Alice: こんにちは、ボブ!
[10:15:13] Bob: やあ、アリス!
ポイント解説
各ユーザーは互いに直接通信せずに、
「ChatRoom(Mediator)」を通じてメッセージをやり取りしているのがポイントです。
サンプルコード2
もう少し実践的なUI連携の例
Mediator
class FormMediator {
constructor() {
this.loginBtn = null;
this.usernameInput = null;
this.passwordInput = null;
}
notify(sender, event) {
if (sender === this.usernameInput || sender === this.passwordInput) {
const canLogin =
this.usernameInput.value.length > 0 && this.passwordInput.value.length > 0;
this.loginBtn.setEnabled(canLogin);
}
}
}
Colleague
class InputField {
constructor(mediator, name) {
this.mediator = mediator;
this.name = name;
this.value = "";
}
setValue(value) {
this.value = value;
this.mediator.notify(this, "input");
}
}
class Button {
constructor(mediator, name) {
this.mediator = mediator;
this.name = name;
this.enabled = false;
}
setEnabled(state) {
this.enabled = state;
console.log(`${this.name} ボタン: ${state ? "有効" : "無効"}`);
}
}
実行
const mediator = new FormMediator();
const username = new InputField(mediator, "ユーザー名");
const password = new InputField(mediator, "パスワード");
const loginBtn = new Button(mediator, "ログイン");
mediator.usernameInput = username;
mediator.passwordInput = password;
mediator.loginBtn = loginBtn;
username.setValue("koji");
password.setValue("1234");
// 👉 ログイン ボタン: 有効
ポイント解説
username と password はお互いを知らない状態です。
それでも Mediator が両者の状態を監視して連携を制御しているところを理解してみましょう。
setEnabledで、ログインボタンを有効にする処理判定を、仲介役が行っているイメージですね。
メリット
・オブジェクト間の依存関係を減らせる(疎結合)
・各コンポーネントを独立して再利用しやすい
・通信ルールを1箇所に集約でき、制御が明確になる
デメリット
・Mediatorにロジックを集めすぎると、「神オブジェクト(God Object)化」して逆に複雑化する
・変更の影響範囲がMediator全体に広がる可能性がある
・小規模なアプリではオーバーエンジニアリングになりがち
あとがき
仲介役というと、なんだか仰々しく思えてしまいますが、Validator(バリデーター)のような役割ですね。
バリデーションチェックで、全ての条件が整えば、処理を実行する裁判所的な役割です。
複数条件の判定などでよく使われるというのが分かりますね。
おまけのサンプルコード
Webフォーム(HTML+JS)でMediatorパターンを実装するデモ
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>Mediator Pattern Form Demo</title>
<style>
body { font-family: sans-serif; padding: 20px; }
input { margin: 5px; padding: 5px; }
button { padding: 6px 12px; }
</style>
</head>
<body>
<h2>Mediatorパターンで制御するフォーム</h2>
<input id="name" type="text" placeholder="名前を入力">
<input id="email" type="email" placeholder="メールを入力">
<button id="submit" disabled>送信</button>
<p id="status"></p>
<script>
// === Mediator(調停者) ===
class FormMediator {
constructor(nameInput, emailInput, submitButton, status) {
this.nameInput = nameInput;
this.emailInput = emailInput;
this.submitButton = submitButton;
this.status = status;
// 各コンポーネントからイベントを受け取る
nameInput.addEventListener('input', () => this.notify('inputChanged'));
emailInput.addEventListener('input', () => this.notify('inputChanged'));
submitButton.addEventListener('click', () => this.notify('submit'));
}
notify(event) {
if (event === 'inputChanged') {
const isFilled = this.nameInput.value && this.emailInput.value;
this.submitButton.disabled = !isFilled;
this.status.textContent = isFilled
? "送信できます"
: "すべての項目を入力してください";
}
if (event === 'submit') {
this.status.textContent = `送信完了:${this.nameInput.value} (${this.emailInput.value})`;
this.nameInput.value = '';
this.emailInput.value = '';
this.submitButton.disabled = true;
}
}
}
// === 各要素の取得 ===
const nameInput = document.getElementById('name');
const emailInput = document.getElementById('email');
const submitButton = document.getElementById('submit');
const status = document.getElementById('status');
// === Mediatorを生成して関連付け ===
new FormMediator(nameInput, emailInput, submitButton, status);
</script>
</body>
</html>
ポイント解説
・FormMediator がフォーム全体の状態を監督。
・各 input は Mediator に「変化があった」とだけ通知。
・Mediator が「ボタンを有効化するか」「メッセージを表示するか」を判断。
0 件のコメント:
コメントを投稿