2016-06-15 5 views
1

私たちはいくつかのタイプのリソースを持っており、リソースが健全かどうかをチェックするメソッドを作りたかったのです。リソースの種類は、我々は、標準的なサブクラス化を使用したくなかった非常に不均一であることを考えると、私たちは型クラスを使用することにしました:指定されたリソースが生きているかどうかを確認することができるように型のスカラ型パターンと共分散

trait CanHealthCheck[T] { 
    def isHealthy(t: T): Boolean 
} 

我々はまた、ユーティリティメソッドを持っています/健全かどうか

object LivenessChecker { 
    def isAlive[T](t: T)(implicit canHealthCheck: CanHealthCheck[T]): Boolean = { 
    canHealthCheck.isHealthy(t) 
    } 
} 

データにアクセスするためのリポジトリレイヤーがあります。私たちは、与えられた抽象リポジトリが「健康チェック可能」でなければならないという考えを表現するが、形質を実装するサブクラスに実装の詳細を残したいと思います:

trait UserRepository { 
    def findSomeUser(): User = ??? 

    implicit def isHealthCheckable: CanHealthCheck[UserRepository] 
} 

我々は特定してUserRepositoryサブクラス化したいときに問題が発生しましたCanHealthCheckは、タイプのTにのの共変量ではありません。

class DbUserRepository extends UserRepository { 
    def ping: Boolean = ??? 

    override implicit val isHealthCheckable: CanHealthCheck[UserRepository] = 
    new CanHealthCheck[DbUserRepository] { 
     def isHealthy(db: DbUserRepository) = db.ping 
    } 
} 

そして、これはリポジトリが生きているかどうかを確認しようとしているときに、抽象リポジトリに作用するいくつかのダミー関数の一例です:アイデアは我々のアプリケーションは、UserRepositoryを使用していることである

def someDummyFunction(userRepository: UserRepository) = { 
    if(LivenessChecker.isAlive(userRepository)) // This won't compile 
    userRepository.findSomeUser() 
} 

リポジトリが生存しているかどうかを確認することはできません。リポジトリ抽象化レイヤーを引き続き使用して、与えられた(抽象的な)リポジトリが生存しているかどうかを確認する方法はありますか? typeclassパターンはここで使用する正しいパターンですか?

答えて

0

"タイプ境界"を使用してください。 UserRespository内部isHealthCheckableと少し怪しい何かがあり

class DbUserRepository[U <: UserRepository] extends UserRepository { 
    def ping: Boolean = ??? 

    implicit val isHealthCheckable: CanHealthCheck[U] = 
    new CanHealthCheck[U] { 
     def isHealthy(db: U) = db.ping 
    } 
} 
+0

この問題の解決方法はわかりません。私たちは 'CanHealthCheck [UserRepository]'が必要ですが、あなたの例では 'U <:UserRepository'で' CanHealthCheck [U] 'を取得します。 CanHealthCheckが** Tの共変**ではないことを考えれば、これはうまくいきません。 –

+0

あなたの質問に「CanHealthCheckはタイプTの共変ではありません。私はコードをコンパイルする方法を参照する答えを残しておきます...今のところ: - \ –

1

は、私はあなたのような何かを行うことができ、これをテストすることができませんでしたが、コンパイルしたコードを取得します。 isHealthyメソッドを呼び出すと、UserRepositoryという2つのインスタンスが使用できます。もちろん、t引数として渡されますが、囲むインスタンスのUserRepository.thisも渡されます。

これは間違った兆候です。メソッドが他の場所に書き込まれていなければならないので、これを囲みません。そうでなければ、引数を取るべきではありません。

この2番目のオプションは、オブジェクト指向のサブタイプの方法でUserRepositoryを使用することと矛盾しません。また、すべてのUserRepositoryがヒースチェック可能でなければならないという考え方と一貫しています。ちょうど

trait UserRepository { 
    ... 
    def isHealty: Boolean 
} 

userDirectory.isHealthyを直接呼び出しても問題ありません。しかし、あなたは、その後も簡単に型クラスを実装することができます

object UserRepository { 
    implicit val canHealthCheck = new CanHealthCheck[UserRepository] { 
    def isHealthy(repository: UserRepository) = repository.IsHealthy 
    } 
} 

も、それがすべてで暗黙のインスタンスメソッドが暗黙的スコープに来ているだろうか明確ではなかったことに注意してください。コンパニオンオブジェクトでは、正常に動作します。

+0

私はおそらく何か間違っていることに同意します。問題は、型定義パターンを使用してクライアントが特性にのみ依存するか、または古典的なOO指向のアプローチを使用する必要があるかどうかです。 BTW私は潜在的なクライアントが抽象的なuserRepositoryをどのように使用するかを反映するために質問を更新しました –