l

o

a

d

i

n

g

.

.

.

GoF以外のプログラミング・デザインパターン #28 Event Bus / Pub-Sub

2025/12/19

プログラミング 学習

t f B! P L
eyecatch Event Busは、“メッセージのバス(共通通路)” を中心に、複数のコンポーネントがイベントをやり取りする方式。 Pub-Subは、Event Bus の実装パターンのひとつです。 この連動する2つのパターンについて理解することで、イベント処理を効率的に設計できるようになります。

Event Bus / Pub-Sub の本質

このパターンは、部品同士をゆるく結合(Loosely Coupled)にする仕組みです。 “イベントを発行する側(Publisher)”が、“受け取る側(Subscriber)”を知らなくてよくなるという特徴があります。 システム全体を「通知の流れ」でつなぐ設計を理解しておきましょう。

特徴

Event Bus

・イベントは Bus に投げるだけ。 ・Bus は購読者に一括で配信。 ・発行側と受信側が完全に独立。
[Component A] ↓ (EventBus) ↓ [Component X] [Component Y] [Component Z]

Pub-Sub(Publish–Subscribe)

・Publisher(発行者) : イベントを Publish する ・Subscriber(購読者) : 必要なイベントを Subscribe する 丸ごと一方向なので、依存関係が最小化することができる。

Observer との違い

項目 Observer Pub-Sub(Event Bus)
登録場所 Subject に直接登録 中央の EventBus に登録
双方向性 Subject ↔ Observer が直接関係 Publisher ⇄ Bus ⇄ Subscriber
依存関係 Subject が Observer を知る 完全非依存(疎結合)
適用場面 オブジェクト同士の局所イベント システム全体の通知設計

ポイント

・Event Bus は“イベントを流す中央の通路”。 ・Pub-Sub はそのモデルに基づくデザインパターン。 ・Observer より疎結合で、システム全体の通知に強い。 ・現代の多くのアーキテクチャ(Vue/React、Kafka、Flutter)は Pub-Sub をベースにしている。

サンプルコード1 : 超簡易 Event Bus

class EventBus { constructor() { this.subscribers = {}; } subscribe(event, handler) { if (!this.subscribers[event]) { this.subscribers[event] = []; } this.subscribers[event].push(handler); } publish(event, data) { if (this.subscribers[event]) { this.subscribers[event].forEach(fn => fn(data)); } } } // 使う側 const bus = new EventBus(); // Subscriber bus.subscribe("user:created", (u) => { console.log("ログ: ユーザー作成", u); }); bus.subscribe("user:created", (u) => { console.log("通知メール送信: ", u.name); }); // Publisher bus.publish("user:created", { id: 1, name: "Alice" });

ポイント解説

・Publisher は Subscriber を知らない ・Subscriber は Publisher を知らない ・この2つが"Pub-Sub"の最大の強み。

サンプルコード2 : DOMイベントをPub-Subとして利用

<div id="bus"></div> <script> // EventBusとして使うDOMノード const bus = document.getElementById("bus"); // Subscriber(購読者) bus.addEventListener("user:created", (e) => { console.log("ログ処理:", e.detail); }); bus.addEventListener("user:created", (e) => { console.log("メール送信:", e.detail.name); }); // Publisher(発行者) function createUser(name) { const user = { id: Date.now(), name }; // イベント発行 bus.dispatchEvent(new CustomEvent("user:created", { detail: user })); } // 実行 createUser("Alice"); </script>

ポイント解説

・bus という DOM ノードを EventBus として利用。 ・user:created イベントを購読 ・dispatchEvent() でイベントを発行 ・すべての購読者が通知を受け取る ※DOM は「複数リスナー登録」「イベントバブリング」「カスタムイベント」を標準でサポートしているため、EventBus の役割に向いている。

よく使われる用途

・フロントエンド SPA のグローバルイベント。 ・ゲームのイベント通知(HP減少、アイテム取得)。 ・マイクロサービス間の非同期イベント配送(Kafka)。 ・IoT 温度センサー → メッセージブローカー。 ・UIコンポーネント間通信。

メリット

・コンポーネントが疎結合になる ・横断的な処理(ログ、通知、計測)が分離できる ・機能追加が容易(新しい Subscriber を追加するだけ) ・同期/非同期どちらでも使える

デメリット

・イベントの流れが見えにくい(デバッグが難しい) ・どこでイベントが消費されるか追いにくい ・設計が悪いと「何でもイベント化する地獄」になる

あとがき

イベントを独自で作成するEvent BusとPub-Subの書き方が理解できれば、結構手軽に自分でも使えるイメージが沸きますね。 サンプルコードのように、複数のイベントを一括実行することもできるし、他にも複雑なイベント構築ができるようになります。 Javascriptでのコード記述ですが、他の言語でも独自イベントとして使うこともできそうですね。

人気の投稿

このブログを検索

ごあいさつ

このWebサイトは、独自思考で我が道を行くユゲタの少し尖った思考のTechブログです。 毎日興味がどんどん切り替わるので、テーマはマルチになっています。 もしかしたらアイデアに困っている人の助けになるかもしれません。

ブログ アーカイブ