プログラミング言語のクラスで、私の教授は、壊れやすい基本クラスの問題に対する解決策の 1 つとしてミックスインを引用しています。ウィキペディアも (Ruby) ミックスインを壊れやすい基底クラスの問題の解決策として挙げていましたが、しばらく前に誰かがミックスインへの言及を削除しました。壊れやすい基本クラスの問題に関して、継承よりも何らかの形で利点があるのではないかと私はまだ思っています。そうでなければ、なぜ教授は彼らが助けになると言うでしょうか?
考えられる問題の例を挙げます。これは、教授が問題を説明するために私たちにくれた (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 }
}
問題は、トレイトが機能するかどうかaddAll
が基本クラスでの実装方法に依存することです。つまり、基本クラスによって提供される機能はextends
、Java やその他のプログラミング言語の通常の場合と同様に「脆弱」です。 .
たとえば、上記で定義したようにMyList
とを指定して次のコードを実行すると、 が返されますが、 が返されることが期待されます。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 の専門家ではないことに注意してください。