【问题标题】:encapsulation for mixin's members in ScalaScala 中 mixin 成员的封装
【发布时间】:2015-02-05 16:23:23
【问题描述】:

Scala 中的特征可以用作混合和接口。这会导致一些不一致 - 如果我想关闭 trait 中的某些方法,我不能这样做:

object Library {
    protected trait A { def a: Int = 5 }
    trait B extends A { private override def a: Int = super.a }
    //I want to close `a` memeber for all traits extending B; it's still possible to open it in some another trait `C extends A`, or even `Z extends B with C`
}

// Exiting paste mode, now interpreting.

<console>:10: error: overriding method a in trait A of type => Int;
 method a has weaker access privileges; it should not be private
           trait B extends A { private override def a: Int = super.a }
                                                    ^

LSP 的角度来看,这样的错误完全没问题,因为我(或编译器)可能希望将其转换为超类型A。但如果我只是将它用作混音,我实际上不需要这样做,例如在一些蛋糕图案的变化中。我会做类似的事情:

 import Library._
 object O extends B with K with L with App

就是这样。我什至无法在这里访问 trait A。我知道,有类型推断可能会上升到超类型,但它只是一个“类型行”,所以编译器可以在这里跳过A 并继续(当然这是非常理论上的)。另一个例子 - here 我必须为方法提供默认实现,而我并不真正需要。

我当前使用的解决方案是 OOP 组合,但它不是那么灵活(因为线性化在这里不起作用)并且与混入概念不太兼容。我见过的一些项目,他们实际上做了混合,并且有“超过 9000 个”冗余和可见的成员。几年前,有一个想法是通过指定的with 关键字而不是extends 来“标记”此类mixins 组合,但现在甚至找不到该线程。

那么,对于 ad-hoc 成员封装有什么更好的做法吗?

【问题讨论】:

    标签: scala encapsulation mixins traits


    【解决方案1】:

    这不是通用的解决方案,但可以在一个模块内关闭来自外部世界的方法:

    object Library {
      protected trait A { 
        private[Library] def a: Int = 5 
        private[Library] def b: Int = 7 
      }
      trait B extends A { 
        def b = super.b 
      }
    }
    
    import Library._
    object C extends B
    
    scala> C.a
    <console>:179: error: method a in trait B cannot be accessed in object C
                  C.a
                    ^
    scala> C.b
    res131: Int = 7
    

    所以我们只是在这里反转封装。如果A 也应该开放扩展:

    object Library {
      protected trait _A { 
        private[Library] def a: Int = 5 
        private[Library] def b: Int = 7 
      }
      trait B extends A { /*...*/ }
      trait A extends _A {
        override def a = super.a 
        override def b = super.b
      }
    }
    

    所以,也许太样板了,但至少它有效。

    附:这个想法的部分灵感来自另一个无效的已删除答案:)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-23
      • 2023-03-18
      • 1970-01-01
      • 2011-05-25
      • 2016-07-14
      相关资源
      最近更新 更多