【问题标题】:Case classes in Scala with behaviorScala 中具有行为的案例类
【发布时间】:2013-12-16 12:27:52
【问题描述】:

我有一个具有某些 val 作为参数的 Scala 案例类。我有几个方法可以使用这个案例类。假设我的案例类定义如下:

case class CaseA(a: Int, b: List[CaseB])
case class CaseB(a: Int, b: text, c: Boolean)

CaseA 和 CaseB 都代表我的案例类的域模型。但是当我在我的应用程序中使用它们时,我想根据 CaseB 的布尔字段向 CaseA 添加一些行为。例如,假设在 CaseA 中,val b 有 4 个 CaseB 对象。我想添加一个贯穿 b 的行为,并告诉我 CaseB 中的任何一个元素是否将 val c 设置为 true。

我想出的是 CaseA 的以下实现:

case class CaseA(a: Int, b: List[CaseB], c: Boolean)

但是这种方法的问题在于,当我从数据库加载我的 CaseA 对象时,我不需要 val c,因为 val c 是计算出来的,而不是 CaseA 对象的一部分。我更进一步,将我的 CaseA 修改为如下所示:

case class CaseA(a: Int, b: List[CaseB], c: Option[Boolean])

我可以看到它已经变得丑陋了。如何向我的案例类添加行为,以便 val c 不必是 CaseA 对象的一部分,而是每次在运行时计算?

【问题讨论】:

    标签: class scala case


    【解决方案1】:

    如果您不需要所有元素的 c,我会使用惰性值

    case class CaseB(a:Int,b:String,c:Boolean)
    case class CaseA(a:Int,b:List[CaseB]){
        lazy val c = b exists (_.c)
    }
    
    val ca = CaseA(42, List( 
        CaseB(1,"hello",false),
        CaseB(2,",",false),
        CaseB(3,"world",true))
        )
    
    println(ca.c)
    

    要回答您的一些评论问题,如果您想使用 mixin-trait,您可以执行以下操作:

    case class CaseB(a:Int,b:String,c:Boolean)
    case class CaseA(a:Int,b:List[CaseB])
    trait CanCheck extends CaseA{
        lazy val c = b exists (_.c)
    }
    
    val ca = new CaseA(42, List( 
        CaseB(1,"hello",false),
        CaseB(2,",",false),
        CaseB(3,"world",true))
        ) with CanCheck
    
    println(ca.c)
    

    请注意,您需要使用 new 关键字来完成这项工作

    【讨论】:

    • 如果需要重新计算,只需将“lazy val”与“def”交换即可。用户代码将保持完全相同:)
    【解决方案2】:

    两种方式:

    1) 将 c 定义为 val,甚至更好地定义为 def:

    case class CaseA(a: Int, b: List[CaseB]){
      val c = b.exists(_.c)
    }
    

    2) 使用隐式包装器:

    case class CaseA(a: Int, b: List[CaseB])
    implicit class CaseAC(underlying: CaseA) {
      val c = underlying.b.exists(_.c)
    }
    val x = CaseA(3, Nil)
    // x: CaseA = CaseA(3,List())
    
    x.c
    // Boolean = false
    

    如果你不需要存储c,你可以使用隐式值类,它更薄的包装器

    【讨论】:

      【解决方案3】:

      我不明白你在用数据库做什么。忽略那一点,我会做以下事情:

      case class CaseA(a: Int, b: List[CaseB]){
        val c = b.exists(_.c)
      }
      

      【讨论】:

      • 如何将 b.exisis(_.c) 行为与我的案例类分开?
      • 你可以很容易地用一个函数来做到这一点:def oneIsTrue(ca:CaseA) = ca.b.exists(_.c),但是,你应该考虑这个函数实际上属于哪里。跨度>
      • 我更多地考虑使用具有行为的特征,我以后可以在我的案例类中混合它!
      猜你喜欢
      • 1970-01-01
      • 2016-11-26
      • 2012-10-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-26
      • 2011-10-03
      相关资源
      最近更新 更多