Несколько типов с ИЛИ с одним общим c методом позиционирования - PullRequest
2 голосов
/ 14 февраля 2020

У меня есть два типа данных: String и extension из SpecificRecordBase и несколько методов с одинаковыми бизнес-логиками c для обработки этих данных, за исключением использования 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 в типах generi c?

  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 Ответ

1 голос
/ 14 февраля 2020

К сожалению, сейчас нет оператора типа 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
}

Ad-ho c полиморфный

Также известный как Type Class шаблон. Вы можете извлечь поведение на основе его типа. Это довольно популярный подход, который вы можете увидеть в таких библиотеках, как cats, circe et c. Пожалуйста, смотрите пример кода ниже для получения более подробной информации:

// 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, поэтому, пожалуйста, исправьте меня, если вы найдете некоторые детали, которые не имеют смысла с точки зрения Кафки view.

Надеюсь, это поможет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...