Nous avons plusieurs types de ressources et nous voulions faire une méthode pour vérifier si une ressource est en bonne santé ou non. Étant donné que le type de ressources sont très hétérogènes, nous ne voulions pas utiliser subclassing standard et nous avons décidé d'utiliser une classe de types:Scala typeclass et la covariance
trait CanHealthCheck[T] {
def isHealthy(t: T): Boolean
}
Nous avons aussi une méthode utilitaire pour être en mesure de vérifier si une ressource donnée est vivant/sain ou pas
object LivenessChecker {
def isAlive[T](t: T)(implicit canHealthCheck: CanHealthCheck[T]): Boolean = {
canHealthCheck.isHealthy(t)
}
}
Nous avons une couche de référentiel pour accéder aux données. Nous tenons à exprimer l'idée qu'un référentiel abstrait donné doit être « checkable de santé », mais de laisser les détails de mise en œuvre des sous-classes mise en œuvre du trait:
trait UserRepository {
def findSomeUser(): User = ???
implicit def isHealthCheckable: CanHealthCheck[UserRepository]
}
Le problème se pose quand on veut sous-classe UserRepository avec un particulier mise en œuvre, étant donné que CanHealthCheck n'est pas covariant sur le type T.
class DbUserRepository extends UserRepository {
def ping: Boolean = ???
override implicit val isHealthCheckable: CanHealthCheck[UserRepository] =
new CanHealthCheck[DbUserRepository] {
def isHealthy(db: DbUserRepository) = db.ping
}
}
Et ceci est un exemple d'une fonction factice qui agit sur le dépôt abstrait tout en essayant de vérifier si le dépôt est vivant:
def someDummyFunction(userRepository: UserRepository) = {
if(LivenessChecker.isAlive(userRepository)) // This won't compile
userRepository.findSomeUser()
}
L'idée est que notre application utilise la UserRepository trait et non l'implémentation, et donc nous ne pouvons pas vérifier si le référentiel est vivant ou non. Comment pouvons-nous continuer à utiliser la couche d'abstraction du référentiel et être en mesure de vérifier si un référentiel (abstrait) donné est vivant? Le modèle typeclass est-il le modèle correct à utiliser ici?
Je ne vois pas comment cela résoudra le problème.Nous avons besoin d'un 'CanHealthCheck [UserRepository]' alors que dans notre exemple nous obtenons un 'CanHealthCheck [U]' avec 'U <: UserRepository'. Étant donné que CanHealthCheck n'est pas ** covariant ** sur T, cela ne fonctionnera pas –
Je suis désolé, j'ai raté "CanHealthCheck n'est pas covariant sur le type T" dans votre question. Je vais laisser la réponse comme une référence quant à la façon de compiler le code ... pour l'instant: - \ –