2016-06-15 3 views
1

우리는 여러 가지 유형의 리소스를 가지고 있으며 리소스가 정상적인 지 여부를 확인하는 방법을 만들고 싶습니다. 자원의 종류는 우리가 표준 서브 클래스를 사용하지 않은 매우 이질적인 것을 감안할 때 우리는 typeclass를 사용하기로 결정 : 주어진 자원이 살아 있는지 확인 할 수스칼라 typeclass 패턴 및 공분산

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

우리는 또한 유틸리티 메소드가/건강한가/아니오

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

데이터에 액세스하기위한 저장소 계층이 있습니다. 우리가 특정과 UserRepository 하위 클래스로 할 때

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

    implicit def isHealthCheckable: CanHealthCheck[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 
    } 
} 

그리고 이것은 저장소가 살아 있는지 확인하는 동안 추상 저장소에 작용 몇 가지 더미 기능의 예는 다음과 같습니다

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

아이디어는 우리의 응용 프로그램이 UserRepository를 사용하는 것을 특성이 아니며, 따라서 저장소가 살아 있는지 여부를 확인할 수 없습니다. 저장소 추상화 계층을 계속 사용하고 주어진 (추상) 저장소가 살아 있는지 확인할 수있는 방법은 무엇입니까? 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의 두 인스턴스를 사용할 수 있습니다. 물론 하나는 t 인수로 전달되지만 해당 인스턴스의 UserRepository.this도 전달됩니다.

이것은 잘못된 신호입니다. 메서드는 다른 곳에 쓰여야합니다. 따라서이 메서드를 포함하거나 인수를 가져 오지 않아야합니다.

두 번째 옵션은 개체 지향, 하위 형식 지정 방식 인 UserRepository를 사용하는 것과 일관됩니다. 또한 모든 UserRepository가 히스 검사 가능해야한다는 생각과 일치합니다. 그냥

trait UserRepository { 
    ... 
    def isHealty: Boolean 
} 

userDirectory.isHealthy, 직접 그 전화를 괜찮습니다. 또한 암시 적 인스턴스 메서드는 암시 적 범위로 온 것이 전혀 방법 명확하지 않았다 있습니다

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

:하지만 당신은 쉽게 형태를 구현하고 있습니다. 동반자 개체로, 그것은 잘 작동합니다.

+0

나는 아마 그게 뭔가 잘못되었다는 것에 동의한다. 문제는 우리가 typeclass 패턴을 사용할 수 있고 클라이언트가 특성에만 의존하거나 고전적인 OO 지향 접근 방식을 사용해야하는 경우입니다. BTW 나는 잠재적 인 클라이언트가 추상적 인 userRepository를 어떻게 사용할 것인지를 반영하기 위해이 질문을 업데이트했다. –