在 Scala 中实现抽象 类

Implementing Abstract Classes in Scala

我开始学习 Scala 编程和 OOP 编程。 不明白abstractclass的概念。我读过这个例子:

Consider the task of writing a class for sets of integer numbers with two operations,incl and contains. (s incl x) should return a new set which contains the element x together with all the elements of set s. (s contains x) should return true if the set s contains the element x, and should return false otherwise. The interface of such sets is given by:

abstract class IntSet {
  def incl(x: Int): IntSet
  def contains(x: Int): Boolean
}

Let’s say, we plan to implement sets as binary trees. There are two possible forms of trees. A tree for the empty set, and a tree consisting of an integer and two subtrees. Here are their implementations.

class EmptySet extends IntSet {
  def contains(x: Int): Boolean = false
  def incl(x: Int): IntSet = new NonEmptySet(x, new EmptySet, new EmptySet)
}



class NonEmptySet(elem: Int, left: IntSet, right: IntSet) extends IntSet { 
  def contains(x: Int): Boolean =
    if (x < elem) left contains x
    else if (x > elem) right contains x else true
  def incl(x: Int): IntSet =
    if (x < elem) new NonEmptySet(elem, left incl x, right)
    else if (x > elem) new NonEmptySet(elem, left, right incl x) 
    else this
}

Both EmptySet and NonEmptySet extend class IntSet. This implies that types EmptySet and NonEmptySet conform to type IntSet – a value of type EmptySet or NonEmptySet may be used wherever a value of type IntSet is required.

我不清楚为什么引入匿名 class 是有用的,因为在扩展匿名的两个 class 中再次有 incl 和 contains 的定义。

谢谢!

class 不是匿名的,它只是抽象的。哪个 - 简单来说 - 意味着您无法实例化它。但是,您可以在方法签名中使用它……您永远不会知道哪个实现传递给您的方法,但两者都提供相同的接口来与它们交互(因为它们都是 IntSets)。

如果有帮助,您可以将抽象 class 视为具有方法实现的接口,或作为特征的简单形式。

使用InClass(抽象class,而不是匿名class)的主要优点是它定义了一种元素类型,其实例总是实现inclcontains 因此允许您在管理时抽象实现细节,在您的情况下,设置对象。

一个很好的例子是,你可以有一个集合列表 EmptyNomEmpty 在一起,并使用你的摘要 class 给出的合同模糊地使用它们:

val l = List[IntSet](new EmptySet, new NomEmptySet(1, new EmptySet, new EmptySet)
val setsContainingThree = l.filter(_.contains(3))

您的代码使用了它,请注意我写了 new NomEmptySet(1, new EmptySet, new EmptySet) 但它也可以是:

new NomEmptySet(1, new EmptySet, new NomEmptySet(2, new EmptySet, new EmptySet))

您的 NonEmptySet 构造函数期望 InSet 因此您的实际参数可以是 InSet 的子类型的任何类型,即:EmptySetNonEmptySet.

这不是 Scala 或 Java 的特性,而是 OOP 的基本原则。