我有一个基于Squeryl的应用程序。 我定义我的模型作为案例类,主要是因为我觉得方便的复制方法。
我有两个模型是严格相关。 该字段是相同的,很多操作都是常见的,它们将被存储在同一个数据库表。 但是,有一些行为才有意义在这两种情况之一,或者是有道理的在这两种情况下却是不同的。
到现在为止我只使用了一个单例类,与区分模型的类型的标志,而有所不同基于模型的类型的所有方法都以如果。 这是烦人,不完全类型安全。
我想这样做是因素祖先案例类的常规行为和领域,并有两个实际车型继承它。 但是,据我了解,从案例类继承在斯卡拉令人难以接受的,如果子类本身就是一个案例类(没有我的情况下),甚至禁止。
什么是我应该知道从的情况下,类继承的问题和隐患? 是否有意义我的情况下这样做呢?
我的优选避免壳体类继承不重复的代码的方法是有点明显:创建一个公共(抽象)基类:
abstract class Person {
def name: String
def age: Int
// address and other properties
// methods (ideally only accessors since it is a case class)
}
case class Employer(val name: String, val age: Int, val taxno: Int)
extends Person
case class Employee(val name: String, val age: Int, val salary: Int)
extends Person
如果你想更细粒度,组的属性为个人特质:
trait Identifiable { def name: String }
trait Locatable { def address: String }
// trait Ages { def age: Int }
case class Employer(val name: String, val address: String, val taxno: Int)
extends Identifiable
with Locatable
case class Employee(val name: String, val address: String, val salary: Int)
extends Identifiable
with Locatable
由于这是许多有趣的话题,让我提供一些线索在这里。
你可以用下面的方法去:
// You can mark it as 'sealed'. Explained later.
sealed trait Person {
def name: String
}
case class Employee(
override val name: String,
salary: Int
) extends Person
case class Tourist(
override val name: String,
bored: Boolean
) extends Person
是的,你要复制的字段。 如果你不这样做,它根本就不可能实现平等的正确其他问题之一 。
不过,你不需要复制方法/函数。
如果几个属性的复制是非常对你的重要性,然后用普通班,但请记住,他们不适合FP很好。
另外,您也可以使用,而不是组成继承:
case class Employee(
person: Person,
salary: Int
)
// In code:
val employee = ...
println(employee.person.name)
组合物是有效的,并且你应该考虑,以及健全的策略。
而如果你想知道一个密封的特点意味着 - 它是什么,只能在同一个文件进行扩展。 也就是说,这两种情况下,上面的类必须在同一个文件。 这允许详尽的编译器检查:
val x = Employee(name = "Jack", salary = 50000)
x match {
case Employee(name) => println(s"I'm $name!")
}
给出了一个错误:
warning: match is not exhaustive!
missing combination Tourist
这是非常有用的。 现在,你不会忘记对付其他类型的Person
S(人)。 这基本上什么是Option
Scala的类一样。
如果这不要紧,你,那么你可以把非密封和case类扔进自己的文件。 并与成分也许去。
case类是完美的值对象,不改变任何属性,并可以用等号进行比较,即对象。
但是,在继承的情况下实现equals比较复杂。 考虑两个类:
class Point(x : Int, y : Int)
和
class ColoredPoint( x : Int, y : Int, c : Color) extends Point
因此,根据该定义的重点色(1,4,红色)应该等于该点(1,4),它们是相同的点毕竟。 所以重点色(1,4,蓝)也应该等于点(1,4),对不对? 但是,当然,重点色(1,4,红色)应不等于重点色(1,4,蓝),因为他们有不同的颜色。 你去那里,平等关系的一个基本属性是坏了。
更新
您可以使用继承自性状解决很多的问题,在另一个答案描述。 一个更灵活的选择往往是使用类型类。 看看什么是Scala的类型类有用吗? 或http://www.youtube.com/watch?v=sVMES4RZF-8
在这种情况下,我倾向于使用组成,而不是继承,即
sealed trait IVehicle // tagging trait
case class Vehicle(color: String) extends IVehicle
case class Car(vehicle: Vehicle, doors: Int) extends IVehicle
val vehicle: IVehicle = ...
vehicle match {
case Car(Vehicle(color), doors) => println(s"$color car with $doors doors")
case Vehicle(color) => println(s"$color vehicle")
}
显然,你可以使用更复杂的层次和比赛,但希望这给你的想法。 关键是要采取嵌套提取这种情况下,类提供的优势