扩展涵盖一个或所有子类型的特征,以处理一个,一些或所有子类型

时间:2015-05-22 10:29:08

标签: scala

假设我们有一些小部件,每个小部件都可以执行一些操作。某些操作可以由所有窗口小部件执行,有些操作只能由一种窗口小部件执行。

在代码中,看起来像这样:

trait Widget[T] { def actions: List[Action[T]] }
case class WidgetA(actions: List[Action[WidgetA]]) extends Widget[WidgetA]
case class WidgetB(actions: List[Action[WidgetB]]) extends Widget[WidgetB]
case class WidgetC(actions: List[Action[WidgetC]]) extends Widget[WidgetC]

trait Action[-T <: Widget]

因此Action[Widget]Action[WidgetA]的子类型,可以插入WidgetA的操作列表中。所以这是有效的:

case class UniversalAction() extends Action[Widget]
WidgetA(List(UniversalAction()))

现在,我们希望扩展系统,使Action可以由多种Widget执行,但不能执行Widget的所有类型,即{Action 1}}可以由WidgetAWidgetB执行,但不能由WidgetC执行。所以我想要的是能够说出如下内容:

case class RandomAction() extends Action[WidgetA] with Action[WidgetB]

并将其视为Action[WidgetA]Action[WidgetB],以便以下2个表达式有效:

val xs: List[Action[WidgetA]] = List(RandomAction())
val ys: List[Action[WidgetB]] = List(RandomAction())

但我们不能直接或间接地延长Action两次,那么这样做的正确方法是什么?

注意:尽管可以将特征插入到层次结构中以使其覆盖窗口小部件的某些子集,但在新的窗口小部件类型发挥作用时很快变得难以处理,因此我希望避免这样做。

P.S。问题标题目前不是最好的,如果有人可以提出更准确和描述性的标题,我很乐意改变它。

1 个答案:

答案 0 :(得分:1)

类型,即隐式val和转换可以作为比特征更丰富的类型关系模型。 我试图用隐式转换实现类似的逻辑。

假设我们在这里有更多的业务逻辑:

type CanCopyActions[A <: Widget[A]] = {
  def copy(actions: List[Action[A]]): A
}

trait Widget[A <: Widget[A]] {
  self: A with CanCopyActions[A] =>

  def actions: List[Action[A]]
  def add[B](action: B)(implicit conv: B => Action[A]) = copy(conv(action) :: actions)
  def runall = actions foreach (_(self))
}

trait Action[-A <: Widget[_]] {
  def apply(w: A) {}
}

定义我们的conrete类型:

case class WidgetA(actions: List[Action[WidgetA]]) extends Widget[WidgetA]
case class WidgetB(actions: List[Action[WidgetB]]) extends Widget[WidgetB]
case class WidgetC(actions: List[Action[WidgetC]]) extends Widget[WidgetC]  

object MyActionA extends Action[WidgetA] {
  override def apply(w: WidgetA) = println("action A")
}
object MyActionB extends Action[WidgetB] {
  override def apply(w: WidgetB) = println("action B")
}
object MyActionC extends Action[WidgetC] {
  override def apply(w: WidgetC) = println("action C")
}
object MyAction extends Action[Widget[_]] {
  override def apply(w: Widget[_]) = println("common action")
}

任何类型都可以隐式转换为自身,因此Widget.add将与ad-hoc Action一起使用,但让我们定义一些有趣的内容:

case class \/[A <: Widget[A], B <: Widget[B]](widget: Either[A, B], actions: List[Action[A \/ B]]) extends Widget[A \/ B] {
  def copy(actions: List[Action[A \/ B]]) = \/(widget, actions)
}

implicit def eitherLeftAction[A <: Widget[A], B <: Widget[B]](action: Action[A \/ B]): Action[A] = new Action[A] {
  override def apply(widget: A) = action.apply(\/(Left(widget), Nil))
}
implicit def eitherRightAction[A <: Widget[A], B <: Widget[B]](action: Action[A \/ B]): Action[B] = new Action[B] {
  override def apply(widget: B) = action.apply(\/(Right(widget), Nil))
}

并采取特殊行动:

object MyActionAB extends Action[WidgetA \/ WidgetB] {
  override def apply(w: WidgetA \/ WidgetB) = w.widget match {
    case Left(widgetA) => println("dual action A")
    case Right(widgetB) => println("dual action B")
  }
}

以上所有我们可以运行以下并看到适当的结果:

WidgetA(List(MyActionA)).add(MyAction).add(MyActionAB).runall
WidgetB(List(MyActionB)).add(MyAction).add(MyActionAB).runall
然而

将无法编译:

WidgetC(List(MyActionC)).add(MyAction).add(MyActionAB).runall