ヘッド ファースト デザイン パターン: 1/10


The Head First Design Pattern の本から初めてのデザインを学びました.今日は Observer パターンについて学びました.

Head First Design Patterns によると、Observer パターンはオブジェクト間の 1 対多の依存関係を定義するため、1 つのオブジェクトの状態が変化すると、そのすべての依存関係が通知され、自動的に更新されます.変更を送信するオブジェクトはサブジェクトと呼ばれ、変更を受け取るオブジェクトはオブザーバーと呼ばれます.

また、Observer パターンは Publish-Subcrib パターンとは少し異なります.オブザーバー パターンでは、サブジェクトによってオブザーバーに送信されたイベントをフィルター処理する中間処理はありません.イベントはオブザーバーに直接送信されます.これは、Publish-Subscribe パターンには当てはまりません.パブリッシュ-サブスクライブ パターンでは、パブリッシャー (サブジェクト) によって送信されたイベントは、最初にイベント バスに送られます.次に、イベントバスはイベントをフィルタリングし、それに応じてサブクライバー (オブザーバー) に送信します.

たとえば、Observer パターンを実装するには、Subject と Observer の 2 つのインターフェイスが必要です.

 interface Subject {
    fun registerObserver(o : Observer)
    fun removeObserver(o: Observer)
    fun  notifyObservers()
}

Subject インターフェイスは、サブジェクトの動作を定義します.サブジェクトは、オブザーバーの登録、オブザーバーの削除、オブザーバーへの状態の変化の通知を行うことができます.

interface Observer {
    fun update(title: String, airTime: String)
}

Object インターフェイスは、オブジェクトの動作を定義します.オブジェクトは、アニメの新しい更新を放送時間とともに受け取ることができます.

class AnimeSubject : Subject {
    private val observers = mutableListOf<Observer>()
    private var title: String = ""
    private var airTime: String = ""


    override fun registerObserver(o: Observer) {
        observers.add(o)
    }

    override fun removeObserver(o: Observer) {
        observers.remove(o)
    }

    override fun notifyObservers() {
        observers.forEach { observer: Observer ->
            observer.update(title, airTime)
        }
    }

    fun setAnime(title: String, airTime: String) {
        this.title = title
        this.airTime = airTime
        notifyObservers()
    }
}

AnimeSubjectSubject インターフェイスを実装します.オブザーバーのリストが含まれています. AnimeSubject 状態が変化するたびに、オブザーバーに変化を通知します.

class SanmiObserver(val animeSubject: AnimeSubject) : Observer {
    init {
        animeSubject.registerObserver(this)
    }
    override fun update(title: String, airTime: String) {
        println("Thanks for notifying me about $title airing at $airTime")
    }
}

SanmiObserverObserver インターフェイスを実装します.また、依存関係として AnimeSubject を取ります. AnimeSubject のオブザーバーとして自身を登録する

class AdeObserver(val animeSubject: AnimeSubject) : Observer {
    init {
        animeSubject.registerObserver(this)
    }
    override fun update(title: String, airTime: String) {
        println("Yo for notifying me about $title airing at $airTime")
    }
}



fun main() {
    val animeSubject = AnimeSubject()

    val sanmiObserver = SanmiObserver(animeSubject)
    val adeObserver = AdeObserver(animeSubject)

    animeSubject.setAnime("Tokyo Revenger", "21:30")
}

prints:
Thanks for notifying me about Tokyo Revenger airing at 21:30
Yo for notifying me about Tokyo Revenger airing at 21:30

animeSubject がその状態を変更するたびに、そのオブザーバーに変更が通知されます.

オブザーバー パターンを使用する利点は次のとおりです.
  • サブジェクトとオブザーバーは疎結合であるため、サブジェクトまたはオブザーバーの変更が互いに影響を与えることはありません.これにより、新しいオブザーバーの定義、オブザーバーの追加および削除がいつでも非常に簡単になります.
  • ソフトウェアのさまざまな部分間の通信が容易になります.
  • また、サブジェクトの状態が変わるたびにオブザーバーに通知されるため、新しい情報の存在を毎回取得する必要がないため、使用されるリソースの量も削減されます.

  • たとえば、Android 開発における Observer パターンの一般的な使用例は、onClickListerner の設定、あらゆる種類の変更の登録、recyclerview とフラグメント/アクティビティ間の通信です.