3

以下に概説するように、クラス階層でデータベースストレージを管理する一連のクラスがあり、ケースクラスがコンパニオンオブジェクトの親クラスの保護されたメソッドにアクセスできるようにしたいと考えています:

class TableBase[T] { 
  protected def insert(...):T {...}
  protected def update(...) {...}
  // Other "raw" CRUD-methods that I don't want the 
  // world to have access to
}

object User extends TableBase[User] { 
}

case class User(id:Int, email:String) { 
  // But here it would be really useful to access the "raw" CRUD methods:
  def changeEmail(newEmail:String) = User.update(...)
}

唯一の問題は、User (クラス) が TableBase からの継承チェーンに含まれていないため、User.changeEmail での User.update の呼び出しが不正であることです。

method update in class TableBase cannot be accessed in object models.User 
Access to protected method update not permitted because enclosing class 
class User in package models is not a subclass of class TableBase in package 
models where target is defined

このタイプの呼び出しを許可する (便利な) 方法はありますか?

現時点では、changeEmail タイプの関数をシングルトンに移動する必要があります。これにより、呼び出しコードがかなり冗長になります。または、メソッド シグネチャを複製する必要があります。

4

2 に答える 2

1

考えられる解決策は、次のように、UserとTableBaseの間の「is-a」から「has-a」の関係に切り替えることです。

class TableBase[T] { 
  def insert(...):T {...}
  def update(...) {...}
}

object User { 
  private val db = new TableBase[User]
}

case class User(id:Int, email:String) { 
  def changeEmail(newEmail:String) = User.db.update(...)
}

User内でTableBaseのいくつかの側面をカスタマイズできるようにしたかったのですが、それでも実際には可能であり、次のようにすることで非常に簡単です。

object User { 
  private val db = new TableBase[User] { 
    // Override stuff here
  }
}

実際、これは私が最初に持っていたものよりもはるかに優れた解決策であり、メソッドでの名前の競合を回避します(つまり、ユーザーにパブリック「挿入」を設定する理由があり、部分的に保護されたオーバーロードが発生しないのは良いことです)。

于 2012-09-06T16:02:27.107 に答える
0

インターフェイスをトレイトCrudOps[T]として提供し、別の保護されたトレイトTableBase [T]を派生させて実装を提供し、TableBase[T]からシングルトンオブジェクトを派生させることができます。このように、TableBaseはコンパイルユニットの外部には表示されませんが、クライアントはCrudOps[T]を安全に使用できます。

于 2012-09-06T15:11:15.113 に答える