简体   繁体   中英

Trait vs Abstract class in Scala with constructor parameters

What are the differences among these ways of defining Animal:

First way:

trait Animal {
  def color: String
}

Second way:

trait Animal {
  val color: String
}

Third way:

abstract class Animal(color: String) {}

Dog is a subclass of Animal. Consider the first way and the second way of defining Animal, what are the differences among the following ways of defining Dog:

First way:

case class Dog() extends Animal {
  override def color:String = "black"
}

Second way:

case class Dog() extends Animal {
  val color = "black"
}

Third way:

case class Dog(color: String) extends Animal {}

Forth way:

case class Dog(override val color: String) extends Animal(color) {}

Whoa, a lot to be answered here.

Regarding your first question, if you use a val then all subclasses must also use val. If you use def, subclasses can implement it either using def, val or lazy val. If color is a stable, immutable value, then declaring it as "val" in the trait makes sense since it imposes that all implementations in concrete subclasses will also be immutable.

The third way makes color only available in the constructor body and not visible from the outside. However, if you wrote

abstract class Animal(val color: String) {}

then it would be the same as the second way, only using abstract class instead of the trait. You could create a new animal and access its color attribute.

Regarding dog, defining color as def means that it will be computed every time it is invoked (ie when someone tries to access myDog.color). Defining it as val means that it will be an immutable value calculated once and for all when dog object is created. If it were a lazy val, then it would be calculated once and for all, but not when the dog is created, but when its color attribute is invoked (the calculation is postponed until the point of usage, hence the "lazy").

As I said above, if the Animal trait uses a val, then the Dog must also use a val. If Animal uses a def, then Dog can implement that as a def, val or lazy val.

Third way of writing a Dog is simply providing a parameter in case of writing an Animal with a class parameter (which was also third way in animal case). As I said earlier, in this case you cannot access the color attribute from the outside (that is, have val myDog = new Dog("blue") and access myDog.color).

Fourth way of writing a dog is implementing the Animal in case it was written in the way I have shown you above in the code (with using a val keyword). Now the color attribute will be visible. Override is not mandatory since you are implementing an abstract method, not overriding a concrete method, but you can leave it if you like (this way compiler will warn you if you, say, misspell "color" or someone removes the color from Animal class).

Perhaps this article can help too.

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