swing – Scala Wrapper类通过扩展Component和SequentialContainer.Wrapper特性,我对traits有正确的理解吗?

以下代码来自这篇文章:
How to create Scala swing wrapper classes with SuperMixin?

import scala.swing._
import javax.swing.JPopupMenu

class PopupMenu extends Component with SequentialContainer.Wrapper {
  override lazy val peer: JPopupMenu = new JPopupMenu with SuperMixin

  def show(invoker: Component, x: Int, y: Int): Unit = peer.show(invoker.peer, x, y)
}

我一直在尝试制作自定义包装器,所以需要理解这一点,这很简单,但从那以后
我只是开始熟悉Scala,所以我对性状有点不确定.所以我听到的是,特征就像多重继承,你可以混合搭配吗?

我画了一个图表,表示PopupMenu在整个继承结构中的位置.只是为了澄清一些事情:

1)它似乎覆盖了lazy val peer:来自Component的JComponent,还从SequentialContainer.Wrapper获取contents属性? (紫色文字)是吗?

2)Sequential.Wrapper还有一个抽象的def peer:JComponent ..但是这不是被覆盖的那个,所以这里根本没有使用它?

3)令人困惑的是Component和Sequential.Wrapper有一些相同的属性:它们都有def发布和def订阅(红色文本)..但是popupMenu将使用的是来自Component类的订阅/发布?

4)为什么我们不能写PopupMenu扩展SequentialContainer.Wrapper而不是Component?

希望一下子问题不是太多.非常感谢帮助,我是Scala的初学者..

最佳答案 我会用你问题的数字回答:

>正确
>正确.最高特征是UIElement,它定义了一个抽象成员def peer:java.awt.Component.然后你有Container只添加抽象成员def内容:Seq [Component]能够读取子组件. Container.Wrapper是Container的具体实现,它假设(抽象地)Java对等体是javax.swing.JComponent.请注意,在Java自己的层次结构中,javax.swing.JComponent是java.awt.Component的子类型,因此没有冲突.子类型可以细化其成员的类型(“协方差”). SequentialContainer通过说内容是一个可变缓冲区(而不是只读序列)来优化Container.因此,它的实现SequentialContainer.Wrapper在Container.Wrapper中混合,但用标准的Scala缓冲区替换内容.在任何时候都没有给出具体的同行.为方便起见,Component确实实现了该成员,但是如您所见,最终的类PopupMenu会覆盖对等体.由于类型系统的工作方式,所有参与的特征都可以访问对等体,但只有PopupMenu“知道”该类型已被细化为javax.swing.JPopupMenu.例如,SequentialContainer.Wrapper只知道有一个javax.swing.JComponent,因此它可以使用对等体的这部分API.
> UIElement引入了Publisher特征,因此您可以在UIElement派生的所有类型中找到它.在层次结构中多次出现相同的特征没有任何问题.在最后一个类中,只有一个Publisher实例,它不存在多个“版本”.即使Publisher没有在根目录中定义,但是独立地在例如Component和SequentialContainer.Wrapper中,你只能在最终的类中获得一个实例.
>这很简单.在Scala中,您只能扩展一个类,但可以混合任意数量的特征.组件是一个类,而其他所有其他东西都是特征.它的A类扩展了< trait-or-class>与< trait>与< trait> ….

总而言之,所有GUI元素都继承自trait UIElement,后者由java.awt.Component备份.具有子元素的元素使用特征容器,并且允许您按特定顺序添加和删除元素的所有普通面板类型元素都使用SequentialContainer. (并非所有面板都有顺序,例如BorderPanel没有).这些是抽象接口,为了获得所有必要的实现,你有.Wrapper类型.最后,为了得到一个可用的类,你有一个扩展UIElement的Component,并且要求对等体是javax.swing.JComponent,所以它可以实现所有的标准功能.

实现新的包装器时,通常使用Component并优化对等类型,以便可以访问该对等体的特定功能(例如JPopupMenu的show方法).

点赞