在关于编程语言的课程中,我的教授引用 mixins 作为脆弱基类问题的解决方案之一。Wikipedia 也曾经列出 (Ruby) mixins 作为脆弱基类问题的解决方案,但前段时间有人删除了对 mixins 的引用。我仍然怀疑它们在脆弱的基类问题上可能比继承具有某种优势。否则,为什么教授会说他们有帮助?
我将举一个可能的问题的例子。这是教授给我们用来说明问题的(Java)问题的简单 Scala 实现。
考虑以下基类。假设这是列表的一些非常有效的特殊实现,并且在其上定义了更多操作。
class MyList[T] {
private var list : List[T] = List.empty
def add(el:T) = {
list = el::list
}
def addAll(toAdd:List[T]) : Unit = {
if (!toAdd.isEmpty) {
add(toAdd.head)
addAll(toAdd.tail)
}
}
}
还要考虑以下特征,它应该添加size
到上面的列表中。
trait CountingSet[T] extends MyList[T] {
private var count : Int = 0;
override def add(el:T) = {
count = count + 1
super.add(el)
}
override def addAll(toAdd:List[T]) = {
count = count + toAdd.size;
super.addAll(toAdd);
}
def size : Int = { count }
}
问题是 trait 是否有效取决于我们addAll
在基类中的实现方式,即基类提供的功能是“脆弱的”,就像extends
Java 或任何其他编程语言中的正则一样.
例如,如果我们使用上面定义的MyList
and运行以下代码,我们会得到 back ,而我们期望得到。CountingSet
5
2
object Main {
def main(args:Array[String]) : Unit = {
val myCountingSet = new MyList[Int] with CountingSet[Int]
myCountingSet.addAll(List(1,2))
println(myCountingSet.size) // Prints 5
}
}
如果我们addAll
在基类 (!) 中进行如下更改,则该特征CountingSet
按预期工作。
class MyList[T] {
private var list : List[T] = List.empty
def add(el:T) = {
list = el::list
}
def addAll(toAdd:List[T]) : Unit = {
var t = toAdd;
while(!t.isEmpty) {
list = t.head::list
t = t.tail
}
}
}
请记住,我不是 Scala 专家!