Scala中mixin成员的封装 [英] encapsulation for mixin's members in Scala

查看:114
本文介绍了Scala中mixin成员的封装的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Scala中的特性既可以用作mixins也可以用作接口.这会导致一些不一致的情况-如果我想关闭trait中的某些方法,我将无法做到这一点:

Traits in Scala can be used as both mixins and interfaces. It leads to some inconsistence - if I want to close some method inside trait, I just can't do that:

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.但是,如果我只是将其用作混入,则实际上不需要这样做,例如在某些Cake-pattern模式变化中.我会做类似的事情:

Such error is totally fine from LSP-perspective as I (or compiler) may want to cast it to the supertype A. But if i'm just using it as mix-in I never need to do that actually, for instance in some Cake-pattern variation. I'll do something like:

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

就是这样.我什至无法在此处访问特征A.我知道,有类型推断可能会上升为超类型,但这只是类型线",因此编译器可以在这里跳过A并继续(当然,这是非常非常理论上的).另一个示例-在此处,我必须为方法提供默认实现,而我并不是真正需要的.

and that's it. I can't even access trait A here. I know, there is type inference which may go up to super-type, but it's just a "line of types" so compiler could just skip A here and go on (of course it's very very theoretical). Another example - here I had to provide default implementation for method, which I don't really need.

我当前使用的解决方案是OOP-composition,但是它不那么灵活(因为线性化在这里不起作用)并且与混入概念不太兼容.我见过的某些项目实际上是进行混合操作的,并且具有超过9000个"冗余可见成员.几年前,有一种想法通过指定with关键字而不是extends来标记"这样的混合结构,但现在甚至找不到该线程.

The current solution I use is OOP-composition, but it's not so flexible (as linearization doesn't work here) and not much compatible with mix-ins concept. Some projects I've seen, they actually do mixins and have "over9000" redundand visible members. Several years ago there was an idea to "mark" such mixins composition by with keyword specified instead of extends, but can't even find that thread now.

那么,对临时成员封装是否有更好的做法?

So, is there any better practices for ad-hoc member encapsulation?

推荐答案

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

It's not general solution, but it's possible to close methods from the outside world inside one module:

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进行扩展:

So we're just inverting encapsulation here. If A should be also open for extension:

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

因此,也许也是样板,但至少它可以工作.

So, maybe too boilerplate, but at least it works.

P.S.这个想法部分受另一个无效的答案的启发:)

P.S. The idea is partially inspired by another deleted answer which didn't work :)

这篇关于Scala中mixin成员的封装的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆