JavaScriptのデザインパターン:Observerパターンでイベント駆動アーキテクチャを構築
- 作成日 2025.02.10
- javascript
- javascript
Observerパターンは、オブジェクト間の依存関係を管理し、イベント駆動型アーキテクチャを実現するためのデザインパターンです。本記事では、JavaScriptでObserverパターンを活用して効率的なコードを構築する方法を説明します。
目次
Observerパターンとは
Observerパターンは、あるオブジェクトの状態が変化した際に、その変化を他の関連オブジェクトに通知する仕組みです。
基本的なObserverの構造
基本的なObserverパターンの構造をコードで示します。
class Subject {
constructor() {
this.observers = [];
}
addObserver(observer) {
this.observers.push(observer);
}
removeObserver(observer) {
this.observers = this.observers.filter(obs => obs !== observer);
}
notifyObservers(data) {
this.observers.forEach(observer => observer.update(data));
}
}
class Observer {
update(data) {
console.log('Observer received data:', data);
}
}Observerの登録と通知
Observerを登録し、イベント発生時に通知を送る例を示します。
const subject = new Subject();
const observer1 = new Observer();
const observer2 = new Observer();
subject.addObserver(observer1);
subject.addObserver(observer2);
subject.notifyObservers('Event occurred');
// Observer received data: Event occurred
// Observer received data: Event occurredObserverパターンの応用
イベント駆動型システムでの具体的な利用例を示します。
class EventManager {
constructor() {
this.events = {};
}
subscribe(event, listener) {
if (!this.events[event]) {
this.events[event] = [];
}
this.events[event].push(listener);
}
unsubscribe(event, listener) {
if (this.events[event]) {
this.events[event] = this.events[event].filter(l => l !== listener);
}
}
emit(event, data) {
if (this.events[event]) {
this.events[event].forEach(listener => listener(data));
}
}
}
// 使用例
const eventManager = new EventManager();
function onUserLogin(data) {
console.log('User logged in:', data);
}
eventManager.subscribe('login', onUserLogin);
eventManager.emit('login', { username: 'JohnDoe' });
// User logged in: { username: 'JohnDoe' }DOMイベントリスナーとしてのObserverパターン
DOMイベントリスナーはObserverパターンの一種です。
document.getElementById('button').addEventListener('click', () => {
console.log('Button clicked');
});Observerパターンのカスタム実装
独自のイベントリスナーを作成する例です。
class CustomEventEmitter {
constructor() {
this.listeners = {};
}
on(event, callback) {
if (!this.listeners[event]) {
this.listeners[event] = [];
}
this.listeners[event].push(callback);
}
off(event, callback) {
if (this.listeners[event]) {
this.listeners[event] = this.listeners[event].filter(cb => cb !== callback);
}
}
trigger(event, data) {
if (this.listeners[event]) {
this.listeners[event].forEach(callback => callback(data));
}
}
}
// 使用例
const emitter = new CustomEventEmitter();
function handleEvent(data) {
console.log('Event handled with data:', data);
}
emitter.on('myEvent', handleEvent);
emitter.trigger('myEvent', { key: 'value' });
// Event handled with data: { key: 'value' }Observerパターンのメリット
– コードの再利用性向上
– モジュール間の疎結合
– 拡張性の確保
Observerパターンのデメリット
– 複雑性の増加
– メモリリークのリスク
Async/Awaitとの組み合わせ
非同期処理を伴うObserverの例です。
class AsyncObserver {
async update(data) {
console.log('Async observer processing data:', data);
await new Promise(resolve => setTimeout(resolve, 1000));
console.log('Data processed');
}
}
const asyncObserver = new AsyncObserver();
subject.addObserver(asyncObserver);
subject.notifyObservers('Async event');
// Async observer processing data: Async event
// (1秒後)
// Data processedObserverパターンを利用する場面
– ユーザーインターフェイスの状態管理 – イベント駆動型プログラミング – データバインディング
他のデザインパターンとの比較
ObserverパターンとPub/Subパターンの違いについて考えます。
まとめ
Observerパターンを使用すると、イベント駆動型アーキテクチャの実装が容易になり、モジュール間の疎結合を実現できます。適切に使用することで、柔軟で保守性の高いアプリケーションを構築することが可能です。
-
前の記事
Vue 3でのプロパティ APIとイベントハンドリングの見直し 2025.02.10
-
次の記事
Rocky LinuxでのLVM(Logical Volume Manager)の利用方法 2025.02.10
コメントを書く