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

时间:2014-02-13 09:44:55

标签: swing scala inheritance mixins 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类的subscribe / publish ?

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

希望一下子问题不是太多。非常感谢帮助,我是Scala的初学者.. diagram representing the inheritance/trait relationship leading up to popupMenu

1 个答案:

答案 0 :(得分:2)

我会回答你的问题:

  1. 正确

  2. 正确。最高特征是UIElement,它定义了抽象成员def peer: java.awt.Component。然后你有Container只需添加 abstract 成员def contents: Seq[Component]就可以读取子组件。 Container.WrapperContainer具体实现,它假设(抽象地)Java对等体是javax.swing.JComponent。请注意,在Java自己的层次结构中,javax.swing.JComponentjava.awt.Component的子类型,因此没有冲突。子类型可以细化其成员的类型(“协方差”)。 SequentialContainer通过说Container可变缓冲区(而不是只读序列)来优化contents。因此,其实现 SequentialContainer.Wrapper混合在Container.Wrapper中,但用标准的Scala缓冲区替换contents。在任何时候都没有给出具体的peer。为方便起见,Component确实实现了该成员,但正如您所见,最终的类PopupMenu会覆盖peer。由于类型系统的工作方式,所有参与的特征都可以访问peer,但只有PopupMenu“知道”该类型已被细化为javax.swing.JPopupMenu。例如SequentialContainer.Wrapper只知道有javax.swing.JComponent,因此可以使用对等API的这一部分。

  3. Publisher特征由UIElement引入,因此您可以在UIElement派生的所有类型中找到它。 在层次结构中多次出现相同的特征没有任何问题。在最后一个类中,只有Publisher的一个实例,它不存在多个“版本”。即使Publisher尚未在根目录中定义,但独立于例如ComponentSequentialContainer.Wrapper,您只能在最后一个类中获得一个实例。

  4. 这很简单。在Scala中,您只能扩展一个类,但可以混合任意数量的特征。 Component是一个类,而其他所有其他东西都是特征。这是class A extends <trait-or-class> with <trait> with <trait> ...


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

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