2014-10-21 11 views
2

메시지 처리를 담당하는 수신 메소드 내에서 동일한 유형의 다른 일반 클래스를 만들 수 있도록 메시지 내에서 전달되는 일부 일반 유형에 대한 정보를 보존하려는 경우가 있습니다.akka 메시지 중 유형/클래스 태그 유지

나는 언뜻보기에 TypeTag이 내 가장 친한 친구라고 생각했지만, 이것을 시도한 후에 이것이 최선의 해결책이 아니거나 전혀 해결책이 아닌 것으로 보입니다. 먼저 내가 가지고있는 것과 그 결과에 대해 설명해 드리겠습니다.

메시지의 경우 클래스

trait MessageTypeTag[T] { 
    def typeTag: TypeTag[T] 
} 

case class Message[T](id: Int, payload: T, helper: MyClass[T], 
         cond: Condition[MyClass[T]])(implicit val typeTag: TypeTag[T]) 
      extends MessageTypeTag[T] 

MyClass2의

class MyClass2[+T <: Any](_eval: Option[T] = None) { 
    def getEval = _eval getOrElse None 
} 

방법 수신

def receive() = { 
    case [email protected](id, payload, helper, cond) => { 
    // this prints a proper type tag, i.e. String, because type is known in the runtime 
    println(m.typeTag.tpe) 

    // compiler complains here because it sees m.typeTag as TypeTag[Any], i.e. exact 
    // type is not known in the compile time 
    val temp = new MyClass2[m.typeTag.tpe](...) 
} 
} 

더러운 솔루션 Scala와 akka에 대한 여러 기사, 토론, 문서를 읽은 후 factory method case 클래스를 (호출하여) 몇 가지 더러운 해결책을 제시합니다.

case class Message[T](id: Int, payload: T, helper: MyClass[T], 
         cond: Condition[MyClass[T]])(implicit val typeTag: TypeTag[T]) 
      extends MessageTypeTag[T] { 
    def getMyClass2: MyClass2[T] = { 
    // instantiate an object of type T 
    val bla = typeTag.mirror.runtimeClass(typeTag.tpe).newInstance.asInstanceOf[T] 
    // we can call apply here to populate created object or do whathever is needed 
    ... 
    // instantiate MyClass2 parametrized with type T and return it 
    new MyClass2[T](Some(bla)) 
    } 
} 

이 경우 클래스를 제외한 모든 경량 실제로 경우 클래스 자체의 목적을 패배 때문에 좋은 솔루션/디자인에서 멀리 볼 수 있듯이. 리플렉션 호출이 여기서 코딩되지는 않지만 케이스 클래스 내에서 방금 호출 된 일부 외부 팩토리에서 개선 될 수 있지만이 작업을 수행하기 위해서는 더 나은 접근이 필요하다는 느낌이 들게됩니다.

모든 의견을 보내 주시면 매우 감사하겠습니다. 더 많은 정보가 필요한 경우이를 제공 할 수 있습니다.

그리고 저는 비슷한 문제/해결책이 here으로 묘사되어 왔지만, 더 좋은 방법이 있는지 궁금합니다. 감사.

답변

1

리플렉션을 사용하여 클래스를 인스턴스화 할 수있게하려면 전달해야합니다. 주위를 둘러 볼 방법이 없습니다.

val bla = classTag.runtimeClass.newInstance.asInstanceOf[T] 

를하지만 여전히 매우 추한 : 나는 ClassTag 기반 솔루션이 약간 더 간단하다고 생각합니다.

반사 방식을 사용하는 대신 함수를 사용하여 공장을 전달하는 것이 좋습니다.

case class Message[T](..., factory:() => T) { 
    def getMyClass2 = new MyClass2[T](Some(factory())) 
} 

Message(..., {_ => new SomeTThatTakesArguments(3, 4)}) 

내가 가장 좋은 방법은이 같은 방법으로 유형에 의존하지 않는 있도록 MyClass2을 변경하는 것입니다 의심이 당신이 더 인수 없음의 생성자와 클래스로 작업하거나 일부 설정이 필요 할 수 있습니다 - 아마도 제약 조건을 Message에 포함하거나 완전히 생략 할 수있는 typeclass로 표현할 수 있습니다. 그러나 해당 행에 대한 해결책을 제안하려면 MyClass2을 게시해야합니다.

+0

송수신되는 메시지의 예상되는 양이 방대하기 때문에 실제로 함수로 전달하는 것은 옵션이 아닙니다 (이 수치는 수분 만에 수백만입니다). MyClass2는 T 유형의 결과를 전달하며 메시지가 처리되는 동안이 유형이 보존되거나 알려지는 것이 매우 중요합니다. 이 유형은 int로 코딩하고 필요할 때 검사 할 수 있습니다. 그러나 그것은 내가 처음부터 피하고 싶었던 것입니다. – htomek

+0

팩토리 함수의 인스턴스를 하나만 만들면 메시지에 대한 참조가 포함될 수 있습니다.이 참조는 TypeTag에 대한 참조를 포함하는 것과 다르지 않습니다. 'MyClass2'는 어떻게 생겼습니까? 그것은 무엇을 위해 사용됩니까? 우리가 모든 세부 사항을 가지고 있다면 당신의 질문에 쉽게 답할 수있을 것입니다. – lmm

+0

메시지는 여러 JVM에서 전송되므로 결국에는 참조가되지 않습니다. MyClass2에 대한 자세한 내용을 제공하기 위해 원래 질문을 편집합니다. – htomek

관련 문제