observer-pattern
オブザーバーパターンを用いたイベント駆動通信の実装方法を解説するスキルです。システムの複数箇所が状態変化やイベントに反応する必要がある場合に、疎結合なpublish/subscribe構造を実現したいときに活用してください。
description の原文を見る
Teaches the observer pattern for event-driven communication. Use when you need decoupled publish/subscribe behavior where multiple parts of your system react to state changes or events.
SKILL.md 本文
オブザーバーパターン
目次
オブザーバーパターンを使うことで、特定のオブジェクト(オブザーバー)を別のオブジェクト(オブザーバブル)に_購読_させることができます。イベントが発生するたびに、オブザーバブルはそのすべてのオブザーバーに通知します!
使用場面
- アプリケーションの複数の部分に対して状態変更やイベントについて通知する必要がある場合に使用します
- これはコンポーネント間の イベント駆動型の非同期通信を実装するのに役立ちます
使用してはいけない場面
- 購読者数が非常に多く、通知のパフォーマンスが重要になる場合
- シンプルなコールバックや一対一通信のための直接的な関数呼び出しで十分な場合
- 暗黙的なイベントチェーンからのデバッグの困難さが疎結合のメリットを上回る場合
手順
subscribe、unsubscribe、notifyメソッドを持つ Observable クラスを作成します- 関心の分離を改善するため、オブザーバーをオブザーバブルに疎結合に保ちます
- 複雑なロジックを持つ多くの購読者に通知するときはパフォーマンスに注意します
- より高度なリアクティブプログラミングが必要な場合は、RxJS などのライブラリの使用を検討してください
詳細
オブザーバブルオブジェクトは通常、3つの重要な部分を含みます:
observers: 特定のイベントが発生するたびに通知されるオブザーバーの配列subscribe(): オブザーバをオブザーバーリストに追加するためのメソッドunsubscribe(): オブザーバーをオブザーバーリストから削除するためのメソッドnotify(): 特定のイベントが発生するたびにすべてのオブザーバーに通知するためのメソッド
ES6 クラスを使用してオブザーバブルを作成してみましょう:
class Observable {
constructor() {
this.observers = [];
}
subscribe(func) {
this.observers.push(func);
}
unsubscribe(func) {
this.observers = this.observers.filter((observer) => observer !== func);
}
notify(data) {
this.observers.forEach((observer) => observer(data));
}
}
これでオブザーバーリストに subscribe メソッドでオブザーバーを追加したり、unsubscribe メソッドで削除したり、notify メソッドですべての購読者に通知したりできます。
このオブザーバブルを使って何かを構築してみましょう。Button と Switch の2つのコンポーネントだけで構成された非常にシンプルなアプリがあります。
export default function App() {
return (
<div className="App">
<Button>Click me!</Button>
<FormControlLabel control={<Switch />} />
</div>
);
}
アプリケーションとのユーザーインタラクションを追跡したいと考えています。ユーザーがボタンをクリックするかスイッチを切り替えるたびに、このイベントをタイムスタンプ付きでログしたいのです。ログに記録するだけでなく、イベントが発生するたびに表示されるトースト通知も作成したいです!
ユーザーが handleClick または handleToggle 関数を呼び出すたびに、これらの関数はオブザーバーの notify メソッドを呼び出します。notify メソッドは、handleClick または handleToggle 関数によって渡されたデータをすべての購読者に通知します!
まず、logger と toastify 関数を作成しましょう。これらの関数は最終的に notify メソッドから data を受け取ります。
import { ToastContainer, toast } from "react-toastify";
function logger(data) {
console.log(`${Date.now()} ${data}`);
}
function toastify(data) {
toast(data);
}
export default function App() {
return (
<div className="App">
<Button>Click me!</Button>
<FormControlLabel control={<Switch />} />
<ToastContainer />
</div>
);
}
現在、logger と toastify 関数はオブザーバブルを認識していません。オブザーバブルはまだそれらに通知できません!それらをオブザーバーにするには、オブザーバブルの subscribe メソッドを使用して_購読_する必要があります!
import { ToastContainer, toast } from "react-toastify";
function logger(data) {
console.log(`${Date.now()} ${data}`);
}
function toastify(data) {
toast(data);
}
observable.subscribe(logger);
observable.subscribe(toastify);
export default function App() {
return (
<div className="App">
<Button>Click me!</Button>
<FormControlLabel control={<Switch />} />
<ToastContainer />
</div>
);
}
イベントが発生するたびに、logger と toastify 関数は通知されます。次に、実際にオブザーバブルに通知する関数を実装するだけです。つまり handleClick と handleToggle 関数です!これらの関数はオブザーバブルの notify メソッドを呼び出し、オブザーバーが受け取るべきデータを渡す必要があります。
import { ToastContainer, toast } from "react-toastify";
function logger(data) {
console.log(`${Date.now()} ${data}`);
}
function toastify(data) {
toast(data);
}
observable.subscribe(logger);
observable.subscribe(toastify);
export default function App() {
function handleClick() {
observable.notify("User clicked button!");
}
function handleToggle() {
observable.notify("User toggled switch!");
}
return (
<div className="App">
<Button>Click me!</Button>
<FormControlLabel control={<Switch />} />
<ToastContainer />
</div>
);
}
フロー全体を完成させました。handleClick と handleToggle はオブザーバーの notify メソッドをデータと共に呼び出し、その後オブザーバーは購読者(この場合は logger と toastify 関数)に通知します。
ユーザーがいずれかのコンポーネントと対話するたびに、logger と toastify の両関数が、notify メソッドに渡したデータで通知されます!
オブザーバーパターンは多くの方法で使用できますが、非同期でイベントベースのデータで作業するときに非常に有用です。特定のデータのダウンロードが完了したときに特定のコンポーネントが通知されるようにしたい場合や、ユーザーがメッセージボードに新しいメッセージを送信したときに他のすべてのメンバーが通知される場合があります。
ケーススタディ
オブザーバーパターンを使用する有名なライブラリは RxJS です。RxJS にはオブザーバーパターンで機能する多くの組み込み機能と例があります。
メリット
オブザーバーパターンを使用することは、関心の分離と単一責任の原則を実施する優れた方法です。オブザーバーオブジェクトはオブザーバブルオブジェクトに密結合されておらず、いつでも(解除)結合することができます。オブザーバブルオブジェクトはイベントの監視を担当し、オブザーバーは受け取ったデータを処理するだけです。
デメリット
オブザーバーが複雑になりすぎると、すべての購読者に通知するときにパフォーマンスの問題が発生する可能性があります。
出典
参考資料
ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- patternsdev
- リポジトリ
- patternsdev/skills
- ライセンス
- MIT
- 最終更新
- 不明
Source: https://github.com/patternsdev/skills / ライセンス: MIT
関連スキル
doubt-driven-development
重要な判断はすべて、本番環境への展開前に新しい視点から対抗的レビューを実施します。速度より正確性が重要な場合、不慣れなコードを扱う場合、本番環境・セキュリティに関わるロジック・取り消し不可の操作など影響度が高い場合、または後でバグを修正するよりも今検証する方が効率的な場合に活用してください。
apprun-skills
TypeScriptを使用したAppRunアプリケーションのMVU設計に関する総合的なガイダンスが得られます。コンポーネントパターン、イベントハンドリング、状態管理(非同期ジェネレータを含む)、パラメータと保護機能を備えたルーティング・ナビゲーション、vistestを使用したテストに対応しています。AppRunコンポーネントの設計・レビュー、ルートの配線、状態フローの管理、AppRunテストの作成時に活用してください。
desloppify
コードベースのヘルスチェックと技術負債の追跡ツールです。コード品質、技術負債、デッドコード、大規模ファイル、ゴッドクラス、重複関数、コードスメル、命名規則の問題、インポートサイクル、結合度の問題についてユーザーが質問した場合に使用してください。また、ヘルススコアの確認、次の改善項目の提案、クリーンアップ計画の作成をリクエストされた際にも対応します。29言語に対応しています。
debugging-and-error-recovery
テストが失敗したり、ビルドが壊れたり、動作が期待と異なったり、予期しないエラーが発生したりした場合に、体系的な根本原因デバッグをガイドします。推測ではなく、根本原因を見つけて修正するための体系的なアプローチが必要な場合に使用してください。
test-driven-development
テスト駆動開発により実装を進めます。ロジックの実装、バグの修正、動作の変更など、あらゆる場面で活用できます。コードが正常に動作することを証明する必要がある場合、バグ報告を受けた場合、既存機能を修正する予定がある場合に使用してください。
incremental-implementation
変更を段階的に実施します。複数のファイルに影響する機能や変更を実装する場合に使用してください。大量のコードを一度に書こうとしている場合や、タスクが一度では完結できないほど大きい場合に活用します。