在我的代码库中,我想要远离vars
折射器。代码库结构遵循以下格式:
class Animal {
var name : Option[String] = None
var owner : Option[String] = None
}
case class Dog(breed: String) extends Animal {
//Dog logic
}
此设计的主要原因是信息无法同时提供。
因此,从反序列化json的service A
开始,我收到Animal
(Animal
,Dog
)
val animal = new Animal
animal.name = "My little animal"
然后
def update(animal: Animal) : Unit {
animal match {
case a : Animal => a.owner = Some("Joe") // call to service B
case _ => //handle dog
}
}
update(animal)
问题是:我如何重新设计它以避免Animal
中的可变状态?
在copy
中写一个Animal
方法?有很多字段,可能会产生一些样板
组合物?
制作两个班级case
?
case class Animal (...)
case class Dog(animal: Animal, breed: String)
修改
trait
我仍然需要Animal
的具体实现,因为我将Dogs
和Animals
(实际上是Animal
并且没有子类型)
内置案例类复制方法,不会更新Animal
类的值。因此将使用默认值 - 而不是我想要的。 - 是的,可以创建一个包含所有字段的案例类,但如果我们有100多个字段,它是否实用?
答案 0 :(得分:0)
您可以将其设计为ADT(抽象数据类型),如下所示:
trait Animal {
def name: Option[String]
def owner: Option[String]
}
case class Dog(dog: Option[String] = None, owner: Option[String] = None) extends Animal
对于案例类,您默认使用复制方法!
答案 1 :(得分:0)
一个好的解决方案可能是制作一个指定Animal
行为的特征,
sealed trait Animal {
val name: Option[String]
val owner: Option[String]
}
然后使case class
es为您的动物实例提供类型构造函数。
case class Dog(name: Option[String], owner: Option[String]) extends Animal
现在,update
(changeOwner
)将采用Animal
并同样返回另一个Animal
:
def changeOwner(animal: Animal): Animal = animal match {
case Dog(name, owner) => Dog(name, Some("Joe"))
case _ => animal
}
您将按如下方式使用它:
val dog: Animal = Dog(Some("Doggie"), Some("Jack"))
val newDog: Animal = changeOwner(dog)
另外,从你的代码:
case a : Animal => a.owner = Some("Joe") // call to service B
请注意这一点,因为case
的第一个match
将占用所有动物,因此其他情况(例如,您的Dog
案例将无法访问。