【ITニュース解説】Observer Design Pattern in Javascript
2025年09月29日に「Dev.to」が公開したITニュース「Observer Design Pattern in Javascript」について初心者にもわかりやすく解説しています。
ITニュース概要
Observerパターンは、あるデータやイベントの変化に応じて、それに関心がある複数の機能(オブザーバー)を自動更新する仕組みだ。JavaScriptでは、入力値変更でプログレスバーを更新する際など、イベント連携でよく使われる。変化を伝える側が監視役のリストを管理し、イベント発生時にリスト内の機能に通知する。
ITニュース解説
システムエンジニアを目指す皆さんへ、今回はJavaScriptでよく使われる「Observer(オブザーバー)デザインパターン」について解説する。このパターンは、プログラムの中で「ある状態が変わったら、関連する他の部分にその変化を知らせて、何かをしてもらう」という仕組みを実現するための考え方だ。
想像してみてほしい。ウェブページの中に、数値を入れる入力欄と、その数値に応じて伸び縮みするプログレスバー(進捗状況を示すバー)があるとしよう。入力欄の数値が変わるたびに、プログレスバーも自動的に更新されてほしい。もし、入力欄とプログレスバーが直接つながっていて、入力欄が変わるたびにプログレスバーを更新するコードを毎回書かなければならないとしたら、どうだろうか。プログレスバー以外にも、その数値を使って何か他の処理をしたい部分が出てきたら、入力欄の変更を処理する部分にどんどんコードが追加されて、ごちゃごちゃになってしまうかもしれない。
Observerパターンは、このような問題を解決する。このパターンでは、「監視される側」(これを「Subject(サブジェクト)」または「Publisher(パブリッシャー)」と呼ぶ)と、「監視する側」(これを「Observer(オブザーバー)」と呼ぶ)という二つの役割が登場する。Subjectは自分の状態が変化したときに、自分を監視しているすべてのObserverにその変化を「通知」する。Observerは通知を受け取ると、それに応じて自分の役割を果たす、という仕組みだ。先ほどの例で言えば、数値入力欄がSubject、プログレスバーがObserverにあたる。プログレスバーは入力欄の「イベント」(入力値の変化)を「購読(subscribe)」し、値が変化するたびに通知を受け取って自身を更新するわけだ。
では、このパターンをJavaScriptでどのように実装するのか、具体的なコード例をもとに見ていこう。
まず、数値入力欄がSubjectとして振る舞うための土台を作る。記事の例ではprogressという名前の関数を使って、このSubjectの役割を定義している。このprogress関数は、内部にlistという空の配列を持っている。このlistが、自分を「監視してくれるObserver関数」を登録しておく場所になる。
progress関数には、主に三つのメソッド(機能)がある。
一つ目はsubscribeメソッドだ。これは、新しいObserver関数をlistに追加するためのものだ。例えば、プログレスバーを更新する関数を「監視者」として登録したい場合、このsubscribeメソッドを使って、その関数をlistに加えておく。これで、そのObserver関数はSubjectの状態変化を「購読」したことになる。
二つ目はunsubscribeメソッドで、これはlistから特定のObserver関数を削除するためのものだ。もうそのObserver関数に通知を送る必要がなくなったときに使う。
そして最も重要なのがfireメソッドだ。これは、Subjectの状態が変化したときに、登録されているすべてのObserver関数にその変化を「通知」するためのものだ。fireメソッドは、現在の状態を示すstateという値と、オプションでthisobjというオブジェクトを受け取る。このメソッドが実行されると、listに登録されているすべてのObserver関数を一つずつ取り出し、それぞれを実行する。その際、.callというJavaScriptの機能を使って、state(例えば、入力された数値)をObserver関数に渡し、必要であればthisobjをObserver関数の中のthisとして紐付ける。これにより、各Observer関数は通知されたstateの値を使って、それぞれの処理を実行できるわけだ。
次に、このprogressの仕組みを使って、実際にプログレスバーを動かす部分を見ていこう。
まず、const bar = new progress();として、先ほど定義したprogress関数を元に、具体的なSubjectのインスタンス(実体)を作成する。これが、数値入力の変化を通知する「中心」になる。
そして、applycolorという関数を定義する。このapplycolor関数がObserverの役割を果たす。この関数は引数としてval(数値)を受け取り、その値に応じてプログレスバーの見た目(背景色)を更新する処理を行う。Math.maxやMath.minを使って、valが0から100の範囲に収まるように調整しているのは、プログレスバーが常に適切な範囲で表示されるようにするためだ。
このapplycolor関数を、bar(Subjectのインスタンス)の監視者として登録する。それがbar.subscribe(applycolor);という一行だ。これで、applycolor関数はbarからの通知を待つ状態になる。
最後に、ユーザーが数値入力フィールド(inputという変数で参照されているHTML要素)に何かを入力したときの処理を設定する。これはinput.addEventListener("input", ...)というコードで行われる。「input」イベントは、入力フィールドの値が変更されるたびに発生するイベントだ。このイベントが発生すると、イベントリスナー内の関数が実行される。この関数の中では、まず入力フィールドの現在の値を取得し、数値に変換する。そして、その数値(val)を引数として、bar.fire(val);を呼び出す。
これで一連の連携が完成する。ユーザーが数値入力フィールドに新しい数値を入力すると、input要素から「input」イベントが発生する。このイベントをきっかけに、bar.fire(val)が実行される。fireメソッドは、barに登録されているすべてのObserver(この場合はapplycolor関数)を呼び出し、新しい数値valを渡す。applycolor関数は渡されたvalを受け取り、プログレスバーのスタイルを更新する。結果として、ユーザーは入力フィールドの数値を変更するだけで、プログレスバーがリアルタイムに更新される様子を目にすることになる。
Observerデザインパターンを使うことの大きなメリットは、「疎結合(そけつごう)」と呼ばれる関係を構築できる点だ。Subject(数値入力)はObserver(プログレスバー)が具体的に何をどう更新するのかを知る必要がない。ただ「状態が変わったことを通知する」役割だけを担う。Observerも、Subjectがどのように状態を管理しているかを知る必要がなく、ただ「通知を受け取ったら、自分の役割を果たす」だけだ。これにより、もし将来、数値入力の変化に応じてプログレスバー以外にも別の要素を更新したくなった場合でも、既存のコードに大きな変更を加えることなく、新しいObserver関数を作成してsubscribeするだけで簡単に追加できる。これはプログラムの拡張性や保守性を大きく向上させる。JavaScriptにおけるイベントハンドリングの多くは、このObserverパターンに基づいていると考えると、このパターンの重要性がよくわかるだろう。