Observer Pattern


What is Observer Pattern?


あるクラスが変化すると、別のクラスのパターンを検出して通知することで、あるオブジェクトの状態が変化するたびに、対応する動作が必要になる場合に、傍観者パターンを使用することができる.
->プログラムの場合、そのプログラムの値が変化しているため、すぐにフィードバックする必要があります.

Observer Pattern


- One of the Behavioural Patterns


動作モード
オブジェクトまたはクラス間のアルゴリズムまたは責任割当てモード
1つのオブジェクトで実行できない操作を複数のオブジェクトに割り当て、オブジェクト間の結合を最大限に低減し、モードがクラスに主に適用されるかオブジェクトに適用されるかによって区別します.

- It defines one-many relationship. So when one object changes its state, its dependents are notified.


あるオブジェクトの状態変化に応じて別のオブジェクトの状態を変化させ、一対のNオブジェクト間の依存関係を構成する設計モード.

- Pub-Sub Pattern


Pub-Sub Pattern
通知を受信するオブジェクト(Subscriber)とイベント励起オブジェクト(Publisher)の間にイベントチャネルを配置します.PublisherはSubscriberを知らない場合、イベント発生時にEvent Channelにメッセージを渡し、SubscriberもPublisherに関する情報がない場合は自分に合ったメッセージだけを送信します.(これは、応答を考慮せずに中間オブジェクトにまたがることができるため、非同期です.)
Observer Pattern == Pub-Sub Pattern
傍観者モードの場合、通知を受信した傍観者は、イベントを実行するマスターパブリッシャーに登録する必要があります.したがって、あるオブジェクトの状態が変化すると、そのオブジェクトに依存関係を持つ他のオブジェクトに通知され、情報更新の1対N関係が自動的に確立される.
->オブジェクト間に強い関係がある.これとは異なり、Pub-Subモードはより緩やかな関係を有する.

すなわち、2つのモードの最大の違いは、中間に Message BrokerまたはEvent Busが存在するかどうかである.
ObserverモードはObserverとSubjectが相互に認識していることを示し,Pub-Subモードは互いを全く理解していなくても構わない.
SubjectにObserverを登録し、Subjectから直接Observerに通知します.
しかし、Pub-Subモードの場合、PublisherはSubscriberの位置や存在を知る必要はなく、メッセージキューなどのBrokerロールとしての中間点にメッセージを送信するだけでよい.SubscriberもPublisherの位置や存在を知る必要はなく、Brokerに割り当てられたタスクを監視し、割り当てられたタスクを受信するだけで、PublisherとSubscriberは互いの位置を知る必要はありません.
従って,Pub‐Subモードの結合度はObserverモードに比べて低かった.△依存性が低い.
観察者モードの多くは同期方式で動作するが,Pub−Subモードの多くは非同期方式で動作する.
なぜならBrokerは主にMessageQueueを使用しているからです.
Observerモードは単一ドメインで実装する必要があり、Pub-Subモードはドメイン間で実装することができる.
上記と同様に,アプリケーションのドメインが異なっていてもMessageQueueにアクセスできれば処理できる中間メディアBrokerがある.
Observerと比較したメリットとデメリット
  • の利点:直接的な関係ではないため、コード管理、再利用性、信頼性が高い.Publisherの観点からSubscriberを管理しない.
  • 欠点:
  • はミドルウェアを介して、予想通りにメッセージを伝えることができない可能性があります.
  • Case of Observer Pattern


    Apple Storeがあると仮定すると、周りには全部で5人のバイヤーがいて、そのうちの1人(A)はiPhone 13を購入したいと思っています.Aは毎回アップルストアにiPhone 13の在庫があるかどうかを見に行きます.この場合、1つの方法は、アップルストアにiPhone 13の在庫がある場合、周囲のバイヤーにメールを送ることです.この場合、このメッセージはAにとって適切なフィードバックであるかもしれないが、A以外の4人については適切なフィードバックではない.だから、これは良い接近とは言えない.
    iPhone 13を購入したい購入者にのみメールを送るのが良い方法です.したがって、特定のイベントを購読するオブジェクトのみに対してイベント反応を行い、そのオブジェクトのみを理解することが望ましい.この方式は傍観者モードと呼ぶことができる.
    △ニュース購読も同様の方法で行うことができる.

    Basic Structure of Observer Pattern


    Publisher

  • [] Observers
  • addObserver(), removeObserver(), notifyObservers()
  • Business Logic
  • 傍観者パターンを構成する基本構造の一つはPublisherである.Subjectと呼ばれる人もいます.これには3つの重要な要素があります.
    まず,観察者アレイについては,傍観者への参照を含むアレイである.3つの情報もあります.特定のpublisherのイベントを理解したい場合は、addObserverメソッドでこれらのイベントを追加し、ファイバアレイに参照を含めることができます.また、イベントへの反応を停止したい場合は、フィードバックなしにremoveObserverメソッドでアレイから削除できます.
    最後のビジネスロジックでは、これらのコードは特定のイベントの開始時に実行されます.

    Observer

  • Update()
    傍観者はpublisherの活動に興味のある実体である.傍観者は主にいくつかある.
  • この傍観者はaddObserver法により特定のPublisherを購読する.イベントが発生すると、PublisherはnotifyObserverメソッドを呼び出してファイバの更新メソッドを実行します.

    Protocol (Observer Protocol)

  • Update()
    Publisherがこの更新と呼ばれる方法をどのように使用するかは、プロトコルによって理解できます.
  • When should you use Observer Pattern?


    Whenever multiple entities are interested in the changes of state of an object, you can use Observer Pattern.


    Example-購読サービス


    前の例と同様に、サブスクリプションサービスでは、ファイバ・モードを使用してより効率的に管理できます.
    3名の購読者に対してSubscriberとして指定し、1つのサービスに対してユーザーとして登録し(addObserverを介して)、状況に応じて購読をキャンセルしたユーザーはremoveObserverを使用できます.また,特定のアクティビティを受信した場合,サブスクリプションのユーザに特定のフィードバックのみを送信すればよい.
    例えば、スモッグ濃度通知サービスを考えてみましょう.
    上記の要素に従ってコードを記述します.以下に示します.
    protocol Observer: AnyObject {
        func update(_ temp: Float, density: Float)
    }
    傍観者プロトコルを作成します.
    protocol Observable {
        func addObserver(_ observer: Observer)
        func removeObserver(_ observer: Observer)
    }
    
    class Publisher: Observable {
        var observers = [Observer]()
        
        func addObserver(_ observer: Observer) {
            observers.append(observer)
        }
        
        func removeObserver(_ observer: Observer) {
            observers = observers.filter({ $0 !== observer })
        }
    }
    class DustMeter: Publisher {
        var temperature: Float = 0.0
        var density: Float = 0.0
        
        func notify() {
            for observer in observers {
                observer.update(temperature, density: density)
            }
        }
    }
    Publisherでは、登録、削除、変更に対するフィードバックを実現します.
    class Subscriber: Observer {
        var name: String = ""
        
        init(name: String) {
            self.name = name
        }
        
        func update(_ temp: Float, density: Float) {
            print("\(name)님, 오늘의 온도는 \(temp)이고 미세먼지 농도는 \(density)이에요 😇")
        }
    }
    
    次に、各傍観者に対して特定のイベントの更新関数を具体化する.
    class ViewController: UIViewController {
        
        // MARK: - Properties
        
        let dustMeter = DustMeter()
        
        // MARK: - Life Cycle
        
        override func viewDidLoad() {
            super.viewDidLoad()
            
            // 관찰자
            let user1 = Subscriber(name: "만수")
            let user2 = Subscriber(name: "소연")
            let _ = Subscriber(name: "만동")
            
            // 알림을 받을 유저 추가
            dustMeter.addObserver(user1)
            dustMeter.addObserver(user2)
            
            // 알림을 더이상 받지 않을 유저
            dustMeter.removeObserver(user1)
        }
        
        // MARK: - IB Actions
        
        @IBAction func touchUpButton(_ sender: Any) {
            dustMeter.temperature = 32
            dustMeter.density = 80
            
            dustMeter.notify()
        }
    }
    また、実際に使用する場合は上記のように使用することができます.