我开始学习Scala编程和OOP编程。 我不理解抽象类的概念。我读过这个例子:
考虑使用两个操作(包含和包含)为整数组写一个类的任务。 (s incl x)应返回一个新集合,其中包含元素x以及集合s的所有元素。 (s contains x)如果set包含元素x,则返回true,否则返回false。这些集合的接口由下式给出:
abstract class IntSet {
def incl(x: Int): IntSet
def contains(x: Int): Boolean
}
假设我们计划将集合实现为二叉树。树有两种可能的形式。空集的树,以及由整数和两个子树组成的树。以下是他们的实现。
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
}
EmptySet和NonEmptySet都扩展了IntSet类。这意味着类型EmptySet和NonEmptySet符合IntSet类型 - 类型为EmptySet或NonEmptySet的值可以在需要IntSet类型的值的任何地方使用。
我不清楚为什么引入匿名类是有用的,因为在扩展匿名类的两个类中,还有include和contains的定义。
谢谢!
答案 0 :(得分:0)
这个类不是匿名的,它只是抽象的。哪个 - 简单的话 - 意味着你无法实例化它。但是,您可以在方法签名中使用它...您永远不会知道哪个实现传递给您的方法,但两者都提供了与它们交互的相同接口(因为它们都是IntSet
s)。 / p>
如果有帮助,您可以将抽象类视为与方法实现的接口,或者作为特征的简单形式。
答案 1 :(得分:0)
使用InClass
(它是一个抽象类,而不是一个匿名类)的主要优点是它定义了一个元素类型,其实例总是要实现incl
和contains
因此,允许您在管理(在您的情况下)设置对象时抽象实现细节。
这很好的一个例子是你可以将一组Empty
和NomEmpty
放在一起,并使用你的抽象类给出的契约隐约地使用它们:
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
的子类型的任何类型,即:EmptySet
或{{1} }。
这不是Scala或Java功能,而是OOP的基本原则。