JS でパブリッシュ サブスクライブ モデルを作成する

JS でパブリッシュ サブスクライブ モデルを作成する

パブリッシュ・サブスクライブ・モデルとは何ですか?手書きで書けますか?オブザーバーパターンとは違うのでしょうか? ...

1. シーン紹介

次のようなシナリオを見てみましょう。

Nami

ナミはとても才能があり、多才です。現在、彼女は曲を書くこととビデオを撮影することという2つのスキルを持っています。

彼女はこれらの作品をプラットフォームに投稿する予定です。彼女をフォローしているファンはこれらのコンテンツを受け取ることができます

現在、彼にはルフィ、ゾロ、サンジの3人のファンがいる。

ナミさんが作品を発表するたびに、3人のファンのアカウントに寄せられたメッセージが更新されていきます。

では、コードで表現してみましょう。

定数ルフィ = {
  更新: 関数 (曲、ビデオ) {
    console.log(曲、ビデオ);
  },
};
定数ゾロ = {
  更新: 関数 (曲、ビデオ) {
    console.log(曲、ビデオ);
  },
};
定数サンジ = {
  更新: 関数 (曲、ビデオ) {
    console.log(曲、ビデオ);
  },
};

定数ナミ = {
  // このメソッドはナミの作業が更新されるたびに呼び出されます workUpdate: function () {
    // 作品を取得します const songs = this.getSongs();
    const ビデオ = this.getVideos();

    //アカウント更新 luffy.update(songs, videos);
    zoro.update(曲、ビデオ);
    sanji.update(曲、ビデオ);
  },
  getSongs: 関数 () {
    "mp3"を返します。
  },
  getVideos: 関数 () {
    "mp4"を返します。
  },
};

ここで問題が起こります

  • Nami別のファンでRobinを獲得した場合、 robinオブジェクトを追加し、 workUpdateメソッドを変更する必要があります。
  • Nami小説を書くという新しいスキルがある場合、パラメータが 1 つ増えたため、各ファン オブジェクトのworkUpdate関数とupdateメソッドの両方を変更する必要があります。

何か問題が見つかりましたか?

ファン オブジェクトとインフルエンサー オブジェクト間の結合が高すぎるため、それぞれを独立してスケーリングすることが困難になります。

2 コードの最適化

2.1 ファンを増やす問題を解決する

まず最初の問題を解決して、ファンを追加するときにworkUpdateメソッドを変更する必要がないようにしましょう。

まず、「大きな V」を Star クラスに抽象化し、配列fansを使用してファン リストを保存し、ファンを追加するためのメソッドaddFans追加します。

クラス スター {
  コンストラクタ() {
    this.fans = [];
  }
  ファンを追加します(ファン) {
    this.fans.push(ファン)
  }
  作業更新() {
    const songs = this.getSongs();
    const ビデオ = this.getVideos();
    this.fans.forEach((item) => item.update(songs, videos));
  }
  getSongs() {
    "MP3"を返します。
  }
  動画を取得する() {
    "MP4"を返します。
  }
}

次に、「ファン」を Fan クラスに抽象化します。ファン オブジェクトを作成するときに、「big V」オブジェクトを渡し、big V のaddFansメソッドを呼び出してファン リストに追加します。

クラスファン{
  コンストラクタ(名前、星) {
    this.name = 名前
    this.star = 星
    this.star.addFans(これ)
  }
  更新(曲、ビデオ) {
    console.log(曲、ビデオ);
  }
}


ファンを追加するためにコードを変更する必要がなくなりました

const nami = 新しい Star()
const luffy = new Fan("luffy", nami);
const zoro = new Fan("zoro", nami);
const sanji = new Fan("sanji", nami);
const robin = new Fan("robin", nami);
nami.workUpdate()

2.2 作品追加の問題を解決する

big V の作業を保存するためのworks配列を追加し、それにgetsetメソッドを追加します。

クラス スター {
  コンストラクタ() {
    this.fans = [];
    これは動作します = [];
  }
  ファンを追加します(ファン) {
    this.fans.push(ファン);
  }
  setWorks(作業) {
    this.works.push(作業);
    // 作業を追加した後、更新メソッドを呼び出します this.workUpdate();
  }
  getWorks() {
    this.works を返します。
  }
  作業更新() {
    this.fans.forEach((item) => item.update());
  }
}


それに応じて Fan クラスを変更します。

クラスファン{
  コンストラクタ(名前、星) {
    this.name = 名前
    this.star = 星
    this.star.addFans(これ)
  }
  アップデート() {
    console.log(`${this.name}:${this.star.getWorks()}`)
  }
}


これで、大きな V では、コードを変更して動作を追加する必要がなくなりました。

const nami = new Star();
nami.setWorks('song')
nami.setWorks('ビデオ')
nami.setWorks('小説')
const luffy = new Fan("luffy", nami);
const zoro = new Fan("zoro", nami);
const sanji = new Fan("sanji", nami);
nami.workUpdate();

3 オブザーバーパターン

ご覧のとおり、上記の例では、 namiオブジェクトと複数のファン オブジェクトの間に 1 対多の依存関係があります。nami オブジェクトに作業の更新があると、彼女をフォローしているすべてのnamiオブジェクトに通知が送信されます。

実際、これは観察者モードです

オブザーバー パターン:オブジェクト間の 1 対多の依存関係を定義します。オブジェクトの状態が変化すると、それに依存するすべてのオブジェクトに通知され、自動的に更新されます。

2.2 ではコードをさらに抽象化します。

「ファン」はObserverとみなされ、「大きなV」は観察の対象、つまりSubjectとみなされます。

Subjectオブザーバー リストobserverList (元々は fans 配列) を維持します。 Subjectの状態が変化すると (original workUpdate)、notify (original workUpdate ) メソッドを呼び出してすべてのオブザーバーに通知され、それぞれのupdateメソッドが実行されます。

具体的なコードは次のとおりです。

//オブザーバー: サブジェクトクラスSubject {
  コンストラクタ() {
    this.observerList = [];
    // サブジェクトの状態を表します this.state = 0;
  }
  オブザーバーを追加します(オブザーバー) {
    this.observerList.push(オブザーバー);
  }
  // テーマの状態を変更する setState(state) {
    this.state = 状態;
    //状態が変化したら、すべてのオブザーバーに通知します this.notify();
  }
  状態を取得する() {
    this.state を返します。
  }
  通知() {
    this.observerList.forEach((オブザーバー) => observer.update());
  }
}

//オブザーバークラスオブザーバー{
  コンストラクタ(名前, 件名) {
    this.name = 名前;
    this.subject = 件名;
    this.subject.addObserver(これ);
  }
  アップデート() {
    console.log(`${this.name}:${this.subject.state}`);
  }
}

4人のエージェントが登場

大手Vはビジネスで忙しいため、アーティストとファンのつながりを維持するためのエージェントが必要です。

ブローカーの職務には以下が含まれます。

  • ビッグVのファンを維持するために、エージェントはファンリストを持っている
  • ビッグVの新作はエージェントに引き渡され、エージェントはファンリスト内のファンに新作を届ける役割を担います。

次のようにクラスに抽象化します。

クラスマネージャー{
  コンストラクタ() {
    this.fans = [];
    これは動作します = [];
  }
  ファンを追加します(ファン) {
    this.fans.push(ファン);
  }
  setWorks(作業) {
    this.works.push(作業);
    // 作業を追加した後、更新メソッドを呼び出します this.workUpdate();
  }
  getWorks() {
    this.works を返します。
  }
  作業更新() {
    this.fans.forEach((item) => item.update());
  }
}

えっと?このコードを以前どこで見たことがありますか?

はい、クラス名が変更されていることを除けば、2.2 の Star クラスとまったく同じです。

それで、これをやる意味はあるのでしょうか?

実際、コードはまったく同じです。2.2 の Star クラスでは、公開 (つまり、作品の公開) と購読 (つまり、ファンのリストの維持) に関連する関数のみを記述しており、Star クラス自体には、コンテンツの作成など、この作業以外にも多くの機能がある可能性があります。

ここでStarクラスからパブリッシュとサブスクリプションの作業を抽出し、 Managerに完全に責任を持たせます。 Starクラスは、作成が完了したら作業をManagerに引き渡すだけで済みます。

一方、 Fan Starと直接やりとりすることはなくなりました。ファンが関心があるのは作品を受け取れるかどうかだけなので、 Managerと直接やりとりすることになります。 Fan Managerを購読し (この動作は、 Managerが管理するファン リストにファンを追加することと同じです)、 Managerから希望する作品を取得します。

したがって、Star と Fan のコードは次のようになります。

クラス スター {
  コンストラクタ() {}
  // 作成 create(manager) {
    // 作成した新しい作業をエージェントに送信します。 manager.setWorks("new work");
  }
}

クラスファン{
  コンストラクタ(名前、マネージャ) {
    this.name = 名前;
    this.manager = マネージャー;
    this.manager.addFans(これ);
  }
  アップデート() {
    console.log(`${this.name}:${this.manager.getWorks()}`);
  }
}

5 パブリッシュ・サブスクライブモデル

以前は、パブリッシュとサブスクライブを担当するブローカーを使用し、 StarFan直接やり取りできないようにすることで、2 つを切り離す効果を実現していました。

これはパブリッシュ・サブスクライブモデルです

4 ではマネージャーをさらに抽象化します。

「ファン」をSubscriberと考えてください。「ビッグ V」をコンテンツの発行者(パブリッシャー/サブスクライブ モデルではPublisherと呼ばれます)と考えてください。「ブローカー」をパブリッシュ/サブスクライブ センター(または仲介人、 Broker )と考えてください。

具体的なコードは次のとおりです。

//パブリッシュおよびサブスクライブ スケジューリング センター クラス Broker {
  コンストラクタ() {
    this.subscribers = [];
    // サブジェクトの状態を表します this.state = 0;
  }
  // 購読購読(購読者) {
    this.subscribers.push(サブスクライバー);
  }
  // テーマの状態を変更する setState(state) {
    this.state = 状態;
    //状態が変化したら、公開します。this.publish();
  }
  状態を取得する() {
    this.state を返します。
  }
  // 公開 publish() {
    this.subscribers.forEach((subscriber) => subscriber.update());
  }
}

// パブリッシャークラス Publisher {
  コンストラクタ() {}
  状態の変更(ブローカー、状態) {
    ブローカーの状態を設定します。
  }
}

クラス サブスクライバー {
  コンストラクタ(名前、ブローカー) {
    this.name = 名前;
    this.broker = ブローカー;
    this.broker.subscribe(これを);
  }
  アップデート() {
    console.log(`${this.name}:${this.broker.getState()}`);
  }
}

実行して効果を確認してみましょう:

// ディスパッチセンターを作成する const broker = new Broker()
// パブリッシャーを作成する constpublisher = new Publisher()
// サブスクライバーを作成する const subscribe1 = new Subscriber('s1', broker)
const subscribe2 = 新しいサブスクライバー('s2', ブローカー)
const subscribe3 = 新しいサブスクライバー('s3'、ブローカー)
// パブリッシャーは状態を変更し、ディスパッチ センターに通知します。ディスパッチ センターは各サブスクライバーに通知します。publisher.changeState(broker, 1)


6 オブザーバーモードとパブリッシュ・サブスクライブモードの比較

役割の数に関して

  • オブザーバーパターンには、オブザーバーとオブザーブドの2つの役割しかありません。
  • パブリッシュ・サブスクライブモデルには、パブリッシャー、サブスクライバー、仲介者(パブリッシュ・サブスクライブセンター)の3つの役割があります。

結合度から

  • オブザーバー モードは疎結合状態です。つまり、2 つは依然として相互作用しますが、互いに影響を与えることなく、相互に拡張することが容易です。
  • パブリッシュ サブスクライブ モデルでは、パブリッシャーとサブスクライバー間の結合がないため、オブジェクト間の分離の効果が得られます。

意図の観点から

  • 両方: オブジェクト間の 1 対多の依存関係を実装します。オブジェクトの状態が変化すると、それに依存するすべてのオブジェクトに通知され、自動的に更新されます。

JS でパブリッシュ サブスクライブ モデルを作成する方法についての記事はこれで終わりです。JS でパブリッシュ サブスクライブ モデルを作成する方法についての関連コンテンツについては、123WORDPRESS.COM の以前の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • JavaScript デザイン パターン: オブザーバー モードとパブリッシュ サブスクライブ モードの詳細な説明
  • JavaScript の実装とパブリッシュ/サブスクライブ モードの使用に関する詳細な説明
  • JavaScript イベント公開/購読モデルの原理と使用法の分析
  • JavaScript デザインパターン オブザーバーモード(パブリッシュ アンド サブスクライブモード)の原理と実装方法の例
  • js パブリッシュ・サブスクライブモードの例の説明
  • Node.js パブリッシュ・サブスクライブモデルの例
  • JavaScript でのパブリッシュ/サブスクライブパターンの簡単な例

<<:  Kubernetes コントローラーとラベルの簡単な分析

>>:  MySQL Innodbの主な機能挿入バッファ

推薦する

HTML5で見逃せないAPIやヒントのまとめ

これまでのブログ投稿では、HTML 5 ではあまり使われていないが注目すべき API やヒントに焦点...

MySQL データベース内の varchar 型の数値のサイズを比較する方法

テストテーブルを作成する -- ---------------------------- -- ch...

MySQLデータベースのトランザクションとインデックスの詳細な説明

目次1. 事務:取引の 4 つの主な特徴:同時トランザクションはどのような問題を引き起こしますか? ...

JavaScript スコープチェーンの基本原理のグラフィカルな説明

目次序文範囲1. スコープとは何ですか? 2. [[スコープ]] プロパティ3. スコープチェーン4...

ElementUIはカスケードセレクタを実装します

この記事の例では、カスケードセレクターを実装するためのelementUIの具体的なコードを参考までに...

Vueライフサイクルの違いの詳細な説明

ライフサイクル分類vue の各コンポーネントは独立しており、各コンポーネントには独自のライフサイクル...

両端揃えレイアウトを実現する CSS 列のサンプルコード

1. 堂々巡りいろいろ試行錯誤した結果、均等割り付けレイアウトを実現する最も簡単な方法は CSS ...

Ubuntu 20.04 ベスト設定ガイド (初心者向け)

1. システム構成1. sudoパスワードをオフにするsudo コマンドを使用するたびにパスワード...

html 内の絶対パス URL と相対パス URL、サブディレクトリ、親ディレクトリ、ルート ディレクトリ

絶対 URL は、インターネット上の特定のファイルに必要なすべてのコンテンツを表すために使用されます...

IISMonitor を使用して Web ページを監視し、IIS を自動的に再起動します。

目次1. ツールの紹介2. ワークフロー3. 操作インターフェースとパラメータ設定(1)監視と再起動...

MySQL の効率的なクエリの左結合とグループ化 (プラス インデックス)

mysql 効率的なクエリMySQL は、左結合の速度を上げるために group by を犠牲にし...

Unicode の数学記号の概要

数学、物理学、および一部の科学技術分野で使用される特殊記号は多数あります。Unicode コードには...

CentOS 7 に MySQL 8 をインストールするための詳細なチュートリアル

準備するこの記事の環境情報: ソフトウェアバージョンセントOSセントOS7.4マイグレーション8.0...

Vue のグローバル ウォーターマーク実装例

目次1. 透かしのJsファイルを作成する2. 導入操作2.1 App.vueや他のページでの参照2....

MYSQL データベースの基礎 - 結合操作の原理

結合では、ネスト ループ結合アルゴリズムが使用されます。ネスト ループ結合には 3 つの種類がありま...