[英]Inheritance in scala
创建子类的实例但键入到其超类中时,子类的成员不可访问,为什么? 输入子类的超类的用例是什么?
class Fruits{
val fruit=12
}
class Apple extends Fruits{
val apple = 90
}
class Orange extends Fruits{
val orange = 9
}
val aa:Fruits = new Apple
//aa.apple ,This is not accessible, but I have created an instance of Apple, and class Apple contains apple
val ab:Apple = new Apple
ab.apple //Ok
对比变量aa
的静态类型(编译时)与运行时类型
val aa: Fruit = new Apple
| |
static type runtime type
关键是要理解编译器在运行时不知道类型,只验证静态类型指定的约束。 因为您使用类型注释:Fruit
in aa: Fruit
明确指示编译器,编译器不知道aa
在运行时实际上是Apple
。 因此aa.apple
是一个编译器错误,因为Fruit
没有字段apple
。
继承的一个用例是启用子类型多态性:
trait Shape {
def area: Double
}
class Circle(val radius: Float) extends Shape {
override def area: Double = radius * radius * Math.PI
}
class Rectangle(val width: Double, val height: Double) extends Shape {
override def area: Double = width * height
}
object ShapeArea {
def area(shape: Shape): Double = shape.area // <=== define method once for all kinds of shape
}
import ShapeArea._
area(new Circle(2)) // res0: Double = 12.566370614359172
area(new Rectangle(2, 3)) // res1: Double = 6.0
作为旁注,在惯用的函数式编程 Scala 中,存在一种替代的临时多态(类型类)方法:
sealed trait Shape
case class Circle(radius: Float) extends Shape
case class Rectangle(width: Double, height: Double) extends Shape
trait Area[T <: Shape] {
def area(shape: T): Double
}
object Area {
def area[T <: Shape](shape: T)(implicit ev: Area[T]): Double = ev.area(shape) // <== define method once for all kinds of shape
implicit val circleArea: Area[Circle] =
(circle) => circle.radius * circle.radius * Math.PI
implicit val rectangleArea: Area[Rectangle] =
(rectangle) => rectangle.height * rectangle.width
}
import Area._
area(Circle(2)) // res0: Double = 12.566370614359172
area(Rectangle(2, 3)) // res1: Double = 6.0
这有助于明确限制可访问/公开的有关引用对象的信息量; 它可以被视为一种信息隐藏形式。 避免意外依赖有关对象的无关信息可能很有用。
正如其他答案已经指出的那样,原因是编译器不知道aa
是一个苹果。 它认为aa
是水果,因为这里提供了静态类型Fruits
val aa:Fruits = new Apple
在您的代码中。
我们拥有的一个真实用例是 BusinessLayer 和 DataAccessLayer 之间的交互。 BusinessLayer 必须在持久存储中保存一些对象,它会调用 DataAccessLayer 的 save() 方法来实现这一点。 BusinessLayer 不关心 save() 的实现。 它取决于 DataAccessLayer 如何定义 save() 方法。
在生产中, save() 方法将保存对象,例如,在 postgres 数据库中。 但是当我进行一些本地测试时,我可能不想设置 postgres 数据库。 在这种情况下,我想在本地文件系统中将对象另存为 json。 我们怎样才能做到这一点?
我们可以提供 DataAccessLayer 的两种实现: PostgresDataAccessLayer
和JsonDataAccessLayer
。 我的本地测试代码将调用 JsonDataAccessLayer 的save()
方法,而生产代码将调用 PostgresDataAccessLayer 的save()
方法。 代码如下所示:
trait DataAccessLayer {
def save(obj: SomeType)
}
class PostgresDataAccessLayer extends DataAccessLayer {
override def save(obj: SomeType) = {
//logic to save in postgres DB
}
}
class JsonDataAccessLayer extends DataAccessLayer {
override def save(obj: SomeType) = {
//logic to save as json in local file system
}
}
class BusinessLayer(val dal: DataAccessLayer) {
def save(obj: SomeType) ={
dal.save(obj)
}
}
//Production code
val bsLayerProd = new BusinessLayer(new PostgresDataAccessLayer())
//Test Code
val bsLayerTest = new BusinessLayer(new JsonDataAccessLayer())
您可以在实例化时将 DataAccessLayer 的任何实现的对象传递给 BusinessLayer。 在运行时,将调用底层子类的save()
方法。
这种交互,如这里的 BusinessLayer 和 DataAccessLayer 之间,是已知的依赖倒置,即High-level modules should not depend on low-level modules. Both should depend on abstractions
High-level modules should not depend on low-level modules. Both should depend on abstractions
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.