在 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 不是匿名的,它只是抽象的。哪个 - 简单来说 - 意味着您无法实例化它。但是,您可以在方法签名中使用它……您永远不会知道哪个实现传递给您的方法,但两者都提供相同的接口来与它们交互(因为它们都是 IntSet
s)。
如果有帮助,您可以将抽象 class 视为具有方法实现的接口,或作为特征的简单形式。
使用InClass
(抽象class,而不是匿名class)的主要优点是它定义了一种元素类型,其实例总是实现incl
和 contains
因此允许您在管理时抽象实现细节,在您的情况下,设置对象。
一个很好的例子是,你可以有一个集合列表 Empty
和 NomEmpty
在一起,并使用你的摘要 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
的子类型的任何类型,即:EmptySet
或 NonEmptySet
.
这不是 Scala 或 Java 的特性,而是 OOP 的基本原则。
我开始学习 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 不是匿名的,它只是抽象的。哪个 - 简单来说 - 意味着您无法实例化它。但是,您可以在方法签名中使用它……您永远不会知道哪个实现传递给您的方法,但两者都提供相同的接口来与它们交互(因为它们都是 IntSet
s)。
如果有帮助,您可以将抽象 class 视为具有方法实现的接口,或作为特征的简单形式。
使用InClass
(抽象class,而不是匿名class)的主要优点是它定义了一种元素类型,其实例总是实现incl
和 contains
因此允许您在管理时抽象实现细节,在您的情况下,设置对象。
一个很好的例子是,你可以有一个集合列表 Empty
和 NomEmpty
在一起,并使用你的摘要 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
的子类型的任何类型,即:EmptySet
或 NonEmptySet
.
这不是 Scala 或 Java 的特性,而是 OOP 的基本原则。