几种类型或通过一种通用排名方法进行

时间:2020-02-14 08:28:08

标签: scala generics refactoring

我有两种类型的数据:String和从SpecificRecordBase扩展,以及具有相同业务逻辑的几种方法来处理这些数据,除了使用我无法更改的另一个库中的java方法。

  def createResultStreamSpecificRecordBase[T <: SpecificRecordBase](topic: String, source: DataStream[KafkaSourceType])(
      implicit tag: ClassTag[T]): DataStream[T] = {
      // contain calling java method with T <: SpecificRecordBase
      serialize(source, topic)  
      // the same logic
  }

  def createResultStreamString(topic: String, source: DataStream[KafkaSourceType]): DataStream[String] = {
      // dont contain calling java method with T <: SpecificRecordBase
      // the same logic
  }

  def processSpecificRecordBase[T <: SpecificRecordBase](...)(implicit tag: ClassTag[T]): Unit = {
      val stream = createStreamSpecificRecordBase(topic, source)
      // the other the same process actions
  }

  def processString(...): Unit = {
      val stream = createResultStreamString(topic, source)
      // the other the same process actions
  }

我想在处理方法中删除重复的代码,然后写一个。你能写一下怎么做吗?可以在泛型类型中使用类似OR的东西吗?

  def process[T <: SpecificRecordBase ?OR? String](...)(implicit tag: ClassTag[T]): Unit = {
      val stream = createStream(topic, source)

      this match {
          case SpecificRecordBaseRunner() => createStreamSpecificRecordBase(topic, source)
          case StringRunner()             => createStreamString(topic, source)
      }
      // the other process actions
  }

1 个答案:

答案 0 :(得分:1)

不幸的是,目前您没有所描述的OR类型的运算符。好消息,Union Types功能是即将推出的Dotty的一部分: https://dotty.epfl.ch/docs/reference/new-types/union-types.html

现在,此类问题通常可以通过以下方法解决:

总和类型

您可以声明sealed trait,该框将装箱所有可能的实例。 请查看下一个代码示例以获取更多详细信息:

// This is your base of sum type
sealed trait TopicResult

//Declared instances which you need to handle
case class RecordResult[T <: SpecificRecordBase](tag: ClassTag[T]) extends TopicResult
case object StringResult extends TopicResult

//Helper methods goes here for convenience 
object TopicResult {
    def record[T <: SpecificRecordBase](implicit tag: ClassTag[T]): TopicResult = RecordResult(tag)
    def string: TopicResult = StringResult
  }

def process(result: TopicResult /*other arguments*/): Unit = {
  // This pattern matching should be safe, because you know all instances in advance.
  result match {
    case RecordResult(tag) => createStreamSpecificRecordBase(topic, source)
    case StringResult => createStreamString(topic, source)
  }
  /// other operations
}

即席多态

也称为Type Class模式。您可以根据行为类型提取行为。这是一种非常流行的方法,您可能会在catscirce等库中看到这种方法。 请查看下面的代码示例以获取更多详细信息:

// Type dependent logic interface
trait CreateTopic[T] {
 def createTopic(topic: String, source: String): String // put desired result type here
}

object CreateTopic {
  implicit def recordCreateTopic[T <: SpecificRecordBase](implicit tag: ClassTag[T]): CreateTopic[T] = {
    (topic: String, source: String) => ??? // create topic for record base
  }

  implicit val stringCreateTopic: CreateTopic[String] = {
    (topic: String, source: String) => ??? // create topic for record base
  }
}

import CreateTopic._
// implementation will be substituted by compiler based on it's type, from implicit context 
def process[T](/*other arguments*/)(implicit create: CreateTopic[T]): Unit = {
  create.createTopic(topic, source)
  /// other operations
}

不好意思,我不是Kafka专家,所以请纠正我,如果您发现某些部分,从Kafka的角度来看并没有任何意义。

希望这会有所帮助!

相关问题