У нас есть несколько типов ресурсов, и мы хотели бы сделать способ проверить, является ли ресурс здоровым или нет. Учитывая, что тип ресурсов очень неоднороден мы не хотим использовать стандартные подклассы, и мы решили использовать класс типов:Scala typeclass pattern and covariance
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 не является covariant по типу T.
class DbUserRepository extends UserRepository {
def ping: Boolean = ???
override implicit val isHealthCheckable: CanHealthCheck[UserRepository] =
new CanHealthCheck[DbUserRepository] {
def isHealthy(db: DbUserRepository) = db.ping
}
}
И это пример некоторой фиктивной функции, которая действует на абстрактном хранилище при попытке проверить, если хранилище жив:
def someDummyFunction(userRepository: UserRepository) = {
if(LivenessChecker.isAlive(userRepository)) // This won't compile
userRepository.findSomeUser()
}
Идея в том, что наше приложение использует UserRepository а не реализации, и, следовательно, мы не можем проверить, жив ли репозиторий или нет. Как мы можем продолжать использовать слой абстракции репозитория и иметь возможность проверить, жив ли данный (абстрактный) репозиторий? Является ли шаблон typeclass правильным шаблоном для использования здесь?
Не понимаю, как это решить проблему.Нам нужен «CanHealthCheck [UserRepository]», тогда как в вашем примере мы получаем «CanHealthCheck [U]» с 'U <: UserRepository'. Учитывая, что CanHealthCheck не является ** ковариантным ** на T, это не сработает –
Прошу прощения, я пропустил «CanHealthCheck не является ковариантным по типу T» в вашем вопросе. Я оставлю ответ в качестве ссылки на то, как получить код для компиляции ... пока: - \ –