java - 类型类的工厂方法需要 Scala 设计建议

标签 java scala

我正在尝试将 java webapp 转换为 scala。我一直在努力解决类型不匹配错误,这对于确定问题原因没有太大帮助,或者我不知道如何阅读它们。我曾尝试在下面的帖子中询问整个设计中的问题,但看起来这对我没有帮助。
https://stackoverflow.com/questions/32573360/scala-type-mismatch-errors-when-using-type-classes-and-factory-methods

所以我将我的问题分解成小问题。希望这将带来最终的解决方案。有人可以帮我解决 DataContext 和 DataContextBuilder 之间的契约吗?

摘自上述帖子的部分内容:

trait DBObject
trait AggDBObject extends DBObject 
trait RawDBObject extends DBObject 
class Dimensions1Agg extends AggDBObject 
class Dimensions2Agg extends AggDBObject 
class Dimensions1Raw extends RawDBObject

trait IDataContext[A <: DBObject]  {
    var XsummaryData: A = _
    var XByDateData : Map[String, A] = _
    ... more feilds ..

    def restrictAccess = {.. some impl ..}
}

trait IDataContextBuilder[A <: DBObject] {
    def initDataPoints(dataContext: IDataContext[A]): Unit
}
class Dimension1AggContextBuilder extends IDataContextBuilder[Dimension1Agg] {
 .. override method impl..
}


object IDataContext {
  def apply(sId: Int, mId: Int): DataContext[_ <: DBObject]  = { 

    (sId, mId) match {

      case (1, 1) => {
        new DataContext[Dimension1Agg]()
      }
      case (1, 2)  => {
        new DataContext[Dimension1Raw]()
      }
    }
  }
}

我正在创建的对象的 apply 方法的返回类型是否正确?如果我删除它,那么我会在调用站点获得一些复杂的返回类型“val dataContext: DataContext[_ >: Dimension1Agg with Dimension1Raw <: DBObject] with Product with Serialized { .. }”

object IDataContextBuilder {

  def apply(sId: Int, daId: Int): IDataContextBuilder[_ <: DBObject]  = {

    (sId, daId) match {

      case (1, 1) => {
        new Dimension1AggContextBuilder

      }
      case (1, 2) => {
        new Dimension1RawContextBuilder
      }
    }
  }
}

您是否发现上述工厂方法存在任何问题?

将该 DataContext 传递给 DataContextBuilder 时出现以下错误

类型不匹配;找到:IDataContext[_$1],其中类型 $1 <:需要 DBObject:IDataContext[$19]

上面的 _$1 和 _$19 是因为 scalac 无法确定类型吗?

编辑:
将其称为 DataService 类,用于接收用户请求参数、编排上述所有组件并撰写响应。我知道它不起作用,但我正在尝试进行增量重构。 DataService 检查请求参数,将该信息传递给工厂方法以创建多个 DataContext、DataContextBuilder 和 DataWorker;调用所有DataContextBuilder的initDataPoints方法,等待它们完成;调用所有Dataworker的generateView方法,等待它们完成,最后撰写响应。

  1. 初始化每个度量到 DataContext 的映射 varmeasureToDCMap = MapInt, IDataContext[_ <: DBObject]

  2. 对于每个测量器,它执行以下操作来填充 DataContext

    从其工厂方法中获取具体的 DataContext 从其工厂方法获取具体的 DataContextBuilder 调用DataContextBuilder的initDataPoints方法

  3. 此时,所有 DataContext 均已填充相应的 DimensionData。

  4. 为每个指标的每个度量的每个 View 初始化 dataView map (每天的平均推文、每个主题的平均推文、推文率百分位等)

var dataView = MapInt, Map[Int, Map[Int, List[DataView]]] 5) 对于每个 View ,它执行以下操作以生成最终的可见响应

Get concrete ViewWorker . i.e. Metrix1ViewWorker or MetrixViewWorker
Call getData method
  • 生成最终响应
  • 最佳答案

    这里有一种稍微简化的方法。我拿出了一些额外的接口(interface)等:

    trait DBObject
    trait AggDBObject extends DBObject
    trait RawDBObject extends DBObject
    class Dimensions1Agg extends AggDBObject
    class Dimensions2Agg extends AggDBObject
    class Dimensions1Raw extends RawDBObject
    
    class DataContext[A <: DBObject] {
      var XsummaryData: A = _
      var XByDateData : Map[String, A] = _
      def restrictAccess = {
        // .. some impl ..
      }
    }
    
    object DataContext {
    
      def buildDim1Agg() : DataContext[Dimensions1Agg] = {
        // Put the custom code for Dim1 you had at `initDataPoints`
        // ...
        new DataContext[Dimensions1Agg]()
      }
    
      // Add other builder methods if you have lots of custom code, or functions shared across builders.
    
      /** This is your main builder function. 
        * Note that per your request, it is not polymorphic, but tied to a specific type of DBObject.  */
      def apply(sId: Int, mId: Int): DataContext[_ <: DBObject]  = {
    
        (sId, mId) match {
          case (1, 1) => buildDim1Agg()
          case (1, 2)  => buildDim1Agg()
            //... add more cases and a default case.
        }
      }
    }
    

    您没有发布调用所有这些的代码,并且缺少一些上下文,因此我做了很多假设。

    特别是,如果您愿意在这里进行实际的 OOP,您可以将每个 DBObject 类的自定义代码移动到该特定类的构造函数中(每个类现在如何初始化自身),并拥有一个更通用的 DataContext,它不关心它存储的具体类型:

    trait DBObject
    trait AggDBObject extends DBObject
    trait RawDBObject extends DBObject
    
    class Dimensions1Agg extends AggDBObject {
      // Put the custom code you had at `initDataPoints`
    }
    
    class Dimensions2Agg extends AggDBObject {
      // Put the custom code you had at `initDataPoints`
    }
    
    class Dimensions1Raw extends RawDBObject {
      // Put the custom code you had at `initDataPoints`
    }
    
    
    class DataContext(var summaryData: DBObject) {
    
      var XByDateData : Map[String, DBObject] = _
    
      def restrictAccess = {
        // .. some impl ..
      }
    }
    
    object DataContext {
      /** This is your main builder function.
        * This version IS polymorphic, your data context holds a DBObject of the right type, but callers don't need to know which one. */
      def apply(sId: Int, mId: Int): DataContext  = {
    
        (sId, mId) match {
          case (1, 1) => new DataContext(new Dimensions1Agg())
          case (1, 2)  => new DataContext(new Dimensions2Agg())
          //... add more cases and a default case.
        }
      }
    }
    

    希望有帮助。

    关于java - 类型类的工厂方法需要 Scala 设计建议,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32727084/

    相关文章:

    java - 如何在javaFX中扩展 Accordion 的多个TitledPane?

    scala - spark read 在 Scala UDF 函数中不起作用

    Scala 示例代码和弃用问题

    scala - 我的测试中 jacoco4sbt 不是 "detecting"。知道为什么吗?

    scala - 找不到PlayEbean Play 2.5.x

    java - Toolkit 和 PaintComponent 不能一起工作

    java - org.apache.commons.net.ssh 文档

    java - 是否有 Delphi 的 "with..do"Java 等效项?

    java - graphql-java-annotations : Argument must be annotated with @GraphQLName, 否则会失败

    scala - 这是 java lambda 在设计中的限制吗