加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

scala – 做mixins解决脆弱的基类问题吗?

发布时间:2020-12-16 18:11:52 所属栏目:安全 来源:网络整理
导读:在关于编程语言的课程中,我的教授引用mixins作为脆弱基类问题的解决方案之一.维基百科也习惯列出( Ruby)mixins作为脆弱基类问题的解决方案,但前段时间 someone removed对mixins的引用.我仍然怀疑,对于脆弱的基类问题,它们可能在某种程度上优于继承.否则,为什
在关于编程语言的课程中,我的教授引用mixins作为脆弱基类问题的解决方案之一.维基百科也习惯列出( Ruby)mixins作为脆弱基类问题的解决方案,但前段时间 someone removed对mixins的引用.我仍然怀疑,对于脆弱的基类问题,它们可能在某种程度上优于继承.否则,为什么教授会说他们有所帮助?

我举一个可能的问题的例子.这是一个简单的Scala实现(Java)问题,教授给我们解释了这个问题.

考虑以下基类.假设这是列表的一些非常有效的特殊实现,并且在其上定义了更多操作.

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)
        }
    }
}

还要考虑以下特征,它应该在上面的列表中添加大小.

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,即基类提供的功能是“脆弱的”,就像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
        }
    }
}

请记住,我不是斯卡拉专家!

解决方法

Mixins(无论是性状还是其他)不能完全防止脆弱的基类综合症,也不能严格使用界面.原因应该是非常明确的:你可以假设关于你的基类的工作,你也可以假设一个接口.它只会因为它停止并让你思考而有所帮助,并且如果你的界面变得太大会造成样板惩罚,这两种情况往往会限制你进行必要和有效的操作.

特质真正让你摆脱困境的地方就是你已经预料到可能存在问题;然后,您可以参数化您的特性以做适当的事情,或者混合您需要的特性做适当的事情.例如,在Scala集合库中,特征IndexedSeqOptimized不仅用于指示,而且还可以在索引与访问集合元素的任何其他方式一样快的情况下以良好的方式实现各种操作. ArrayBuffer,它包装一个数组,因此具有非常快速的索引访问(实际上,索引是进入数组的唯一方法!)继承自IndexedSeqOptimized.相比之下,Vector可以合理地快速编制索引,但是在没有显式索引的情况下进行遍历会更快,因此它不会.如果IndexedSeqOptimzed不是一个特性,那你就不走运了,因为ArrayBuffer在可变层次结构中而Vector是在不可变层次结构中,因此无法创建一个共同的抽象超类(至少不会没有完全混乱其他的继承的功能).

因此,你脆弱的基类问题没有解决;如果你改变,比如,Traversable的算法实现,使其具有O(n)性能而不是O(1)(可能是为了节省空间),你显然不知道某个孩子是否可能反复使用它并生成O( n ^ 2)性能可能是灾难性的.但是如果你知道,它会使修复变得更容易:只需混合具有O(1)实现的正确特征(并且孩子可以在必要时自由地执行此操作).它有助于将关注点分解为概念上连贯的单位.

所以,总而言之,你可以做任何脆弱的事情.特质是一种工具,明智地使用它可以帮助你健壮,但它们不会保护你免受任何和所有的愚蠢.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读