1. 序章

このチュートリアルでは、オブザーバーパターンについて学習し、Kotlinでのいくつかの異なる実装を見ていきます。

2. オブザーバーパターンとは何ですか?

オブザーバーパターンは、動作ソフトウェアパターンです。 これは、 Gang OfFourによって書かれたDesignPatternsブックで最初に説明されました。

このパターンは、観察されたオブジェクトに発生した変更について複数のオブジェクトに通知するサブスクリプションメカニズムの定義を示しています。 そのため、オブザーバーパターンは分散型イベント駆動型システムで非常に人気があります。

理解を深めるために、読者のBaeldungの例を考えてみましょう。 新しい記事が表示されるたびに読者に通知が届くとしましょう。

この例では、リーダーは Observers であり、BaeldungはObservableです。

3. 標準のオブザーバーパターンの実装

最初の実装として、Gang OfFourの本デザインに従います。 2つのインターフェースで構成されています。

最初のIObserverは、更新アクションを定義します。

interface IObserver {
    fun update()
}

このメソッドは、監視しているオブジェクト内で変更が発生するたびに実行されます。

2番目のインターフェースであるIObservableは、すべてのオブザーバーに関する情報を保持し、それらに更新イベントを送信する役割を果たします。

interface IObservable {
    val observers: ArrayList<IObserver>

    fun add(observer: IObserver) {
        observers.add(observer)
    }

    fun remove(observer: IObserver) {
        observers.remove(observer)
    }

    fun sendUpdateEvent() {
        observers.forEach { it.update() }
    }
}

add()および remove()メソッドを使用することにより、オブザーバーを追跡できます。 sendUpdateEvent()メソッドは、すべてのオブザーバーに更新イベントを送信する役割を果たします。

最も単純な実装では、すべてのオブザーバーを繰り返し処理し、各オブザーバーで update()メソッドをトリガーします。

ここで、これらのインターフェースの実装例を考えてみましょう。

実際には、最新のBaeldung記事に関する情報を保存する簡単なニュースレターエンジンを作成します。 その結果、新しい記事が表示されると、 sendUpdateEvent()メソッドがトリガーされます。

オブザーバーをIObserverインスタンスのリストとして保存し、最新の記事のURLをStringとして保存します。

class BaeldungNewsletter : IObservable {
    override val observers: ArrayList<IObserver> = ArrayList()
    var newestArticleUrl = ""
        set(value) {
            field = value
            sendUpdateEvent()
        }
}

newestArticleUrl プロパティのセッターをオーバーライドすることで、updateメソッドを実行できます。

それでは、オブザーバーの実装を見てみましょう。 簡単にするために、記事のURLをコンソールに出力します。

class BaeldungReader(private var newsletter: BaeldungNewsletter) : IObserver {
    override fun update() {
        println("New Baeldung article: ${newsletter.newestArticleUrl}")
    }
}

4. Kotlinの組み込みの監視可能なデリゲート

Observerパターンを実装する別の方法は、Kotlinの組み込みの監視可能なデリゲートを使用することです。 デリゲートは、指定されたプロパティの読み取りまたは書き込み時に実行されるコールバック関数を返します

この実装では、オブザーバーはラムダ関数のリストとして保存されます。 したがって、記事のURLは以前と同じように String フィールドになりますが、今回はデリゲートが割り当てられています。

class BaeldungNewsletter {
    val newestArticleObservers = mutableListOf<(String) -> Unit>()

    var newestArticleUrl: String by Delegates.observable("") { _, _, newValue ->
        newestArticleObservers.forEach { it(newValue) }
    }
}

この例では、書き込み操作のみをリッスンします。 このため、デリゲートには1つのパラメーターしか定義されていません。

その結果、 newestArticleUrl パラメーターは新しい値を取得し、それをすべてのオブザーバーに渡します。

オブザーバーは、任意の実装を行うことができます。 簡単にするために、ここでも最新の記事のURLをコンソールに出力します。

val newsletter = BaeldungNewsletter()
newsletter.newestArticleObservers.add { newestArticleUrl ->
    println("New Baeldung article: ${newestArticleUrl}")
}

5. 結論

このチュートリアルでは、KotlinでObserverデザインパターンを実装する2つの異なる方法について説明しました。 いつものように、このチュートリアルのすべての例を含むソースコードは、GitHubからで入手できます。