1. ホーム
  2. kotlin

[解決済み] Kotlin データクラスのオーバーライドゲッター

2022-09-02 06:44:35

質問

以下のKotlinのクラスがあるとする。

data class Test(val value: Int)

をどのようにオーバーライドすればよいのでしょうか? Int ゲッターをオーバーライドして、値が負の場合は 0 を返すようにするにはどうしたらよいでしょうか?

これが不可能な場合、適切な結果を得るためのテクニックは何でしょうか?

どのように解決するのですか?

ほぼ丸一年かけて毎日Kotlinを書いた結果、このようにデータクラスをオーバーライドしようとするのは悪い行為であることがわかりました。これには3つの有効なアプローチがあり、それらを提示した後に、他の回答が提案したアプローチがなぜ悪いのかを説明します。

  1. を作成するビジネスロジックを用意する。 data class を作成するビジネスロジックは、 コンストラクタを呼び出す前にその値を 0 以上に変更するようにします。 これはおそらくほとんどの場合において最良のアプローチでしょう。

  2. を使用しないでください。 data class . 通常の class を生成し、IDEに equalshashCode メソッドを提供してくれます(必要ない場合は不要です)。確かに、オブジェクトのプロパティのいずれかが変更された場合は、それを再作成する必要がありますが、オブジェクトの完全な制御が残されています。

    class Test(value: Int) {
      val value: Int = value
        get() = if (field < 0) 0 else field
    
      override fun equals(other: Any?): Boolean {
        if (this === other) return true
        if (other !is Test) return false
        return true
      }
    
      override fun hashCode(): Int {
        return javaClass.hashCode()
      }
    }
    
    
  3. 効果的にオーバーライドされるプライベートな値を持つ代わりに、望むことを行う追加の安全なプロパティをオブジェクト上に作成します。

    data class Test(val value: Int) {
      val safeValue: Int
        get() = if (value < 0) 0 else value
    }
    
    

他の回答が示唆している悪いアプローチ。

data class Test(private val _value: Int) {
  val value: Int
    get() = if (_value < 0) 0 else _value
}

この方法の問題点は データクラス はこのようにデータを変更するためのものではないことです。それらは本当にデータを保持するためだけです。このようなデータクラスのゲッターをオーバーライドすることは、つまり Test(0)Test(-1) ではありません。 equal は互いに異なる hashCode を呼び出すと .value を呼び出すと、同じ結果になります。これは一貫性がなく、あなたにとってはうまくいくかもしれませんが、これがデータクラスであることを知ったあなたのチームの他の人々は、あなたがそれをどのように変更し、それが期待通りに機能しないようにしたかに気づかずに、誤ってそれを使用するかもしれません(例えば、このやり方は MapSet ).