Scala:var到val - 重新设计

时间:2017-12-21 18:35:37

标签: scala oop immutability

在我的代码库中,我想要远离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开始,我收到AnimalAnimalDog

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的具体实现,因为我将DogsAnimals(实际上是Animal并且没有子类型)

  • 复制问题

内置案例类复制方法,不会更新Animal类的值。因此将使用默认值 - 而不是我想要的。 - 是的,可以创建一个包含所有字段的案例类,但如果我们有100多个字段,它是否实用?

2 个答案:

答案 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

现在,updatechangeOwner)将采用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案例将无法访问。