简体   繁体   中英

Case classes in Scala with behavior

I have a Scala case class that has certain val's as parameters. I have a couple of methods that makes use of this case class. Assuming that my case class is defined as follows:

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

Both the CaseA and CaseB represent the domain model of my case classes. But as I use them in my application, I want to add some behavior to CaseA based on CaseB's Boolean field. For example., let us suppose that in CaseA, the val b has 4 CaseB objects. I want to add a behavior that would run through b and tell me if any one of the element in CaseB has the val c set to true.

What I did come up is with the following implementation of CaseA:

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

But the problem with this approach is that when I load my CaseA object from the database, I do not need to have the val c as the val c is computed and not part of CaseA object. I went a step further and modified my CaseA to look like as below:

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

I can see that it is already getting ugly. How can I add behavior to my case classes so that the val c need not be part of the CaseA object and it is rather computed everytime at runtime?

I would use a lazy value in case you don't need the c for all elements

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)

To answer some of your comment questions, if you want to use a mixin-trait, you can do something like the following:

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)

Notice that you need to use the new keyword to make this work

In a two ways:

1) define c as a val, or even better, as a def:

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

2) use implicit wrappers:

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

If you don't need to store c, you might use implicit value classes , which are even thinner wrapper

I don't understand what you are doing with a database. Ignoring that bit, I'd do the following:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM