1前書き

Kotlinプログラミング言語は、クラスプロパティをネイティブにサポートしています。

通常、プロパティは対応するフィールドによって直接裏付けられていますが、必ずしもこのようにする必要はありません。外部の世界に正しく公開されている限り、それらはまだプロパティと見なすことができます。

これはゲッターとセッターでこれを扱うことによって、あるいは

Delegates.

の力を利用することによって達成することができます。

** 2委任プロパティとは

  • 簡単に言うと、委譲プロパティはクラスフィールドに裏付けられていないため、取得および設定を別のコードに委任します。個別のフィールドではなくマップにプロパティ値を格納する。

デリゲートプロパティは、それが使用するプロパティとデリゲートを宣言することによって使用されます。 **

by

キーワードは、プロパティが独自のフィールドではなく提供されたデリゲートによって制御されることを示します。

例えば:

class DelegateExample(map: MutableMap<String, Any?>) {
    var name: String by map
}

これは、

MutableMap

自体がデリゲートであるという事実を使用しているため、そのキーをプロパティとして扱うことができます。


3標準的な委任プロパティ

Kotlin標準ライブラリには、すぐに使用できる一連の標準デリゲートが付属しています。

可変プロパティをバックアップするために

MutableMap

を使用する例をすでに見ました。同様に、

Map

を使用して不変プロパティをバックアップできます。個々のフィールドにプロパティとしてアクセスできますが、変更することはできません。


  • lazy

    デリゲートを使用すると、プロパティの値を最初のアクセス時にのみ計算してからキャッシュに入れることができます。 :

class DatabaseBackedUser(userId: String) {
    val name: String by lazy {
        queryForValue("SELECT name FROM users WHERE userId = :userId", mapOf("userId" to userId)
    }
}


  • observable

    デリゲートは、プロパティの値が変更されたときはいつでもlambdaがトリガーされることを可能にします** 、例えば変更通知や他の関連プロパティの更新を可能にします

class ObservedProperty {
    var name: String by Delegates.observable("<not set>") {
        prop, old, new -> println("Old value: $old, New value: $new")
    }
}


4デリゲートを作成する

すでに存在しているものを使用するのではなく、デリゲートを書きたいことがあります。 ** これは、

ReadOnlyProperty

または__ReadWritePropertyの2つのインターフェースのうちの1つを拡張するクラスを書くことに依存しています。

これらのインタフェースは両方とも

getValue

と呼ばれるメソッドを定義しています。これは、デリゲートされたプロパティの現在の値を読み込むときに使用されます。これは2つの引数を取り、プロパティの値を返します。


  • thisRef

    – プロパティが属するクラスへの参照


  • property

    – 委任されるプロパティの説明


ReadWriteProperty

インタフェースは、プロパティが書き込まれるときにプロパティの現在の値を更新するために使用される

setValue

というメソッドをさらに定義します。これは3つの引数を取り、戻り値はありません。


  • thisRef

    – プロパティが含まれるクラスへの参照


  • property

    – 委譲されているプロパティの説明


  • value

    – プロパティの新しい値

例として、ローカルフィールドではなくデータベース接続に関して常に機能するデリゲートを書きましょう。

class DatabaseDelegate<in R, T>(readQuery: String, writeQuery: String, id: Any) : ReadWriteDelegate<R, T> {
    fun getValue(thisRef: R, property: KProperty<** >): T {
        return queryForValue(readQuery, mapOf("id" to id))
    }

    fun setValue(thisRef: R, property: KProperty<** >, value: T) {
        update(writeQuery, mapOf("id" to id, "value" to value))
    }
}

これは、データベースにアクセスするための2つの最上位関数に依存します。


  • queryForValue

    – これはいくつかのSQLといくつかのバインドを取り、そして

最初の値
**

update

– これはいくつかのSQLといくつかのバインドを取り、それを

UPDATEステートメント

これで、通常のデリゲートと同じようにこれを使用して、クラスをデータベースによって自動的に支援することができます。

class DatabaseUser(userId: String) {
    var name: String by DatabaseDelegate(
      "SELECT name FROM users WHERE userId = :id",
      "UPDATE users SET name = :value WHERE userId = :id",
      userId)
    var email: String by DatabaseDelegate(
      "SELECT email FROM users WHERE userId = :id",
      "UPDATE users SET email = :value WHERE userId = :id",
      userId)
}


5概要

プロパティ委任は強力なテクニックで、他のプロパティの制御を引き継ぐコードを書くことを可能にし、このロジックを異なるクラスの間で簡単に共有するのを助けます。これにより、通常のプロパティアクセスのように見え、感じる堅牢で再利用可能なロジックが可能になります。

この記事の完全に有効な例はhttps://github.com/eugenp/tutorials/tree/master/core-kotlin[GitHubに掲載]を参照してください。