デザインパターン—オブザーバーパターンのクイックガイド。

オブザーバーパターンは、非常に一般的に使用されるパターンです。実際、多くのプログラミング言語/ライブラリで標準化されているのは非常に一般的です。 Javaでは、java.util.Observerに存在します(Java 9では非推奨)。 Pythonでは、apip install pattern-observerに近いものです。 C ++では、boostライブラリ、より正確には#include を使用できます。ただし、業界ではカスタムメイドのソリューションとして広く使用されています。正しく使用し、その複雑さを理解できるようにするために、私たちはそれに飛び込んで探求する必要があります。

オブザーバーパターンは、動作デザインパターンに分類されます。動作設計パターンは、特にクラス/オブジェクト間の通信に関係しています。 [簡単に説明した設計パターンによる]

オブザーバーパターンとは何ですか? (写真のように)アナログテレビを放送するウォーキングモニターとは別に。パターンの目的は、1つのオブジェクトの状態が変化したときに、他のオブジェクトに自動的に通知および更新されるように、1対多の関係を定義することです。より正確には、システムで発生するイベントについて通知されることを望んでいます。パズルのピースを3つのステップにまとめることができます。

ステップ1 —キーワード

キーワードの定義は、この一連のクイックガイドの秘inです。この方法は、設計パターンを真に理解し、それを頭の中でハードコーディングし、他の設計パターンの違いを理解するのに役立ちました。

  1. 件名:情報、データ、またはビジネスロジックのキーパーと見なされます。
  2. 登録/添付:オブザーバーは、変更があったときに通知を受け取りたいため、サブジェクトに登録します。
  3. イベント:イベントは、すべてのオブザーバーに通知されるように、サブジェクトのトリガーとして機能します。
  4. 通知:実装に応じて、サブジェクトはオブザーバーに情報を「プッシュ」するか、オブザーバーがサブジェクトからの情報を必要とする場合に「プル」します。
  5. 更新:オブザーバーは他のオブザーバーとは独立して状態を更新しますが、トリガーされたイベントに応じて状態が変わる場合があります。

ステップ2 —図

この設計を異なるクラスに分割して、これを少し単純化します。

  • ConcreteObserversは、現在のインスタンスに固有の情報を含むクラスです。更新関数は、サブジェクトのnotify()操作によって呼び出されます。オブザーバーは、現在の状態に基づいて個別に更新されます。
  • Observerは、具象オブザーバーの親クラスです。サブジェクトインスタンスが含まれています。オブザーバーは初期化されると、サブジェクトに登録/アタッチします。
  • Subjectクラスには、オブザーバーのリストまたはコレクションがあります。イベントがトリガーされると、更新関数を呼び出すことですべてのオブザーバーをループするnotify()操作を呼び出します。

ステップ3 —例によるコード

gitリポジトリ「Andreas Poyias」または以下のスニペットからクラスごとにコードをコピーし(提供された順序で)、c ++ shell、jdoodle、onlineGDBなどの利用可能なオンラインC ++エディターのいずれかに貼り付けることをお勧めします出力を観察します。次に、以下のコメントまたは説明をお読みください。十分に時間をかけて読んでください(1分を意味します。

例:フットボールの試合を考えてみましょう。多くのサポーターがゲームを見ています。サポーターを年齢別に2つのカテゴリに分けます。チームがゴールを決めると、サポーターは年齢と興奮レベルに応じて異なる反応を示します。
次に、オブザーバーパターンに使用される用語について説明します。

  • ゲームは主題であり、支持者は観察者です。
  • すべてのオブザーバーはサブジェクトにアタッチ/登録され、サッカーチームが得点すると通知されます(トリガーイベントはチームの得点の場合)。
  • オブザーバーは、受信した通知に応じて動作を更新します。

件名
このクラスでは、オブザーバーのリストにアクセスする必要があります。オブザーバーが登録しようとすると、attach(this)関数を呼び出して利用可能なリストに追加します(これはオブザーバーのインスタンスです)。イベントがトリガーされると、wenotify()すべてのオブザーバーが状態を個別に更新します。この例では、オブザーバーのフットボールチームが得点した場合にトリガーされます。

#include 
#include <ベクトル>
名前空間stdを使用します。
クラスSubject {
    vector オブザーバー;
    bool得点; //トリガー、イベント
パブリック:
    //オブザーバーを登録します
    void attach(Observer * obs){
        observers.push_back(obs);
    }
   
   //これはイベントです
   // ifのスコアを設定し、すべてのオブザーバーに通知します
   void setScored(bool Score){
      得点=得点;
      notify();
   }
bool getScored(){
      得点を返す;
   }
   //実装がさらにダウンしていることを通知します
   //スクリプトがコンパイルおよび実行されるように
   void notify();
};

観察者
このクラスは、登録されているサブジェクトに依存しています。具体的なオブザーバーが初期化されると、サブジェクトにアタッチされます。この例では、各オブザーバーの状態は、ゲームに関する彼の興奮レベルです。

クラスオブザーバー
{
    件名* subj;
    int excitementLevel; //状態
  パブリック:
    Observer(Subject * mod、int excLevel)
    {
        subj = mod;
        excitementLevel = excLevel;
        //オブザーバーはサブジェクトに登録/添付します
        subj-> attach(this);
    }
    仮想void update()= 0;
  保護された:
    件名* getSubject(){
       subjを返します。
    }
    void setExcitementLevel(int excLevel){
       excitementLevel = excLevel;
    }
    int getExcitementLevel(){
       興奮レベルを返す;
    }
};

これはtheSubject :: notify()宣言であり、その仕事はすべてのオブザーバーに状態を更新するよう通知することです。

void Subject :: notify(){
  for(int i = 0; i  update();
}

具体的なオブザーバー
具体的なオブザーバーはObserverクラスを継承し、すべてのユーザーが更新機能を持っている必要があります。この例では、具体的なオブザーバーは若いサポーターと古いサポーターを区別しています。興奮レベルが高くなりすぎると、高齢のサポーターには心臓発作のリスクがあり、若いサポーターには飲酒運転のリスクがあります。以下のメイン機能で証明するように、それらの状態は独立して更新されます。

クラスOld_ConcreteObserver:public Observer
{
   パブリック:
     //親コンストラクタを呼び出してサブジェクトに登録します
     Old_ConcreteObserver(Subject * mod、int div)
        :Observer(mod、div){}
     //高齢者の場合、興奮レベルが
     //心臓発作のリスクがある150以上
     void update()
     {
        bool scored = getSubject()-> getScored();
        setExcitementLevel(getExcitementLevel()+ 1);
        if(得点&& getExcitementLevel()> 150)
        {
          cout <<「オールドオブザーバーのチームが得点!!」
               <<「彼の興奮レベルは」
               << getExcitementLevel()
               <<「心臓発作に気をつけろ!」 << endl;
        } else {
          cout <<「チームは得点しなかった。心配することはない」
               << endl;
        }
    } // update()を終了
};
クラスYoung_ConcreteObserver:パブリックオブザーバー
{
   パブリック:
     //親コンストラクタを呼び出してサブジェクトに登録します
     Young_ConcreteObserver(Subject * mod、int div)
       :Observer(mod、div){}
     //高齢者の場合、興奮レベルが
     //心臓発作のリスクがあります
     void update()
     {
        bool scored = getSubject()-> getScored();
        setExcitementLevel(getExcitementLevel()+ 1);
        if(得点&& getExcitementLevel()> 100)
        {
          cout << "若いオブザーバーのチームが得点!!"
               <<「彼の興奮レベルは」
               << getExcitementLevel()
               <<「飲んで運転しないでください!!」 << endl;
        } else {
          cout <<「チームは得点しませんでした。心配する必要はありません」
               << endl;
       }
    } // update()を終了
};

主な機能
具体的なオブザーバーは、Subjectインスタンスに自分自身を登録します。それらの状態は、2番目のパラメーターである興奮レベルです。イベントが「subj.setScored(true)」をトリガーすると、Subject :: notify()が呼び出されて登録済みオブザーバーが更新されます。以下のシナリオでは、3人のオブザーバーがいます。youngObs1は興奮しすぎて飲酒運転のリスクがあり、oldObs1も興奮します(心臓発作の)別のリスクがあります。最後に、最初の若者としても若いyoungObs2は、興奮しすぎていないので心配する必要はありません。

3人のオブザーバーは、状態(興奮レベル)とタイプ(若いまたは古い)に基づいて個別に更新されたことに注意することが重要です。
int main(){
   件名subj;
   Young_ConcreteObserver youngObs1(&subj、100);
   Old_ConcreteObserver oldObs1(&subj、150);
   Young_ConcreteObserver youngObs2(&subj、52);
   subj.setScored(true);
}
//出力
//ヤングオブザーバーのチームが得点!!彼の興奮レベルは101です
//飲んで運転しないでください!!
// Old Observerのチームが得点しました!!彼の興奮レベルは151ウォッチです
//心臓発作から!チームは得点しませんでした。
//心配することはない

Observerパターンの使用にはいくつかの利点があり、このパターンにアプローチする際に注意すべき点がいくつかあります[Pythonデザインパターンの学習]。

  • Observerパターンは、SubjectとObserverが疎結合の設計を提供します。サブジェクトは、ConcreteObserverクラスについて知る必要はありません。新しいオブザーバーはいつでも追加できます。新しいオブザーバーが追加されたときにサブジェクトを変更する必要はありません。オブザーバーとサブジェクトは結び付けられておらず、互いに独立しているため、サブジェクトまたはオブザーバーの変更は互いに影響しません。
  • Observerインターフェースをインスタンス化できるため、構成のオプションはありません。
  • オブザーバーが悪用されると、簡単に複雑さが増し、パフォーマンスの問題が発生する可能性があります。
  • 通知は信頼できない場合があり、競合状態または矛盾を引き起こす可能性があります。

次のブログは、ブリッジのデザインパターンのクイックガイドです。これは、業界で非常に多く使用されている構造設計パターンです。ブログの投稿にいいね/拍手して、アカウントをフォローすることを忘れないでください。これは、私が仲間の開発者を助けて、書き続けるように私を押してくれたという満足感を与えるためです。知りたい特定のデザインパターンがある場合は、今後お知らせできるようにお知らせください。

デザインパターンに関するその他のクイックガイド:

  1. デザインパターン— Abstract Factoryのクイックガイド。
  2. デザインパターン—ブリッジパターンのクイックガイド。
  3. デザインパターン—ビルダーパターンのクイックガイド。
  4. デザインパターン—デコレータパターンのクイックガイド。
  5. デザインパターン—ファサードパターンのクイックガイド。
  6. デザインパターン—オブザーバーパターンのクイックガイド。
  7. デザインパターン—シングルトンパターンのクイックガイド。