设计问题:尝试使用scala类型边界来避免代码重复

时间:2012-10-04 19:36:12

标签: scala design-patterns code-duplication

我是Scala的新手,我正在尝试使用类型边界来避免代码重复在以下代码中(从不相关的东西中清除):

trait StandardStep1[-I1] {
  def next_step(i:I1):StandardStep2
}

trait StandardStep2

trait UniqueStep1[-I1] extends StandardStep1[I1] {
  def next_step(i:I1):UniqueStep2
}

trait UniqueStep2 extends StandardStep2

class DoubleStandardStep1[-IL,-IR](left:StandardStep1[IL], right:StandardStep1[IR]) extends StandardStep1[(IL,IR)] {
  def next_step(i:(IL,IR)) = {
    val (i_left, i_right) = i
    val new_left = left.next_step(i_left)
    val new_right = right.next_step(i_right)
    new DoubleStandardStep2(new_left, new_right)
  }
}

class DoubleStandardStep2(left:StandardStep2, right:StandardStep2) extends StandardStep2

class DoubleUniqueStep1[-IL,-IR](left:UniqueStep1[IL], right:UniqueStep1[IR]) extends UniqueStep1[(IL,IR)] {
  def next_step(i:(IL,IR)) = {
    val (i_left, i_right) = i
    val new_left = left.next_step(i_left)
    val new_right = right.next_step(i_right)
    new DoubleUniqueStep2(new_left, new_right)
  }
}

class DoubleUniqueStep2(left:UniqueStep2, right:UniqueStep2) extends UniqueStep2

说明:

StandardStep1表示某个状态机中的一个步骤,并且具有next_step操作,可为给定输入提供StandardStep2

UniqueStep1是一种特殊类型的StandardStep1,当UniqueStep2被调用时会提供next_step - 显然UniqueStep2必须从{{1}继承为此。

现在我必须写一个 DoubleStep 包装器:StandardStep2包装DoubleStandardStep1 s,并在调用StandardStep1时返回DoubleStandardStep2next_step执行相同的操作,但会返回DoubleUniqueStep1

* DoubleStep * s'DoubleUniqueStep2的实现有明显的代码重复:它们都将输入分成next_stepi_left并调用其包裹的步骤'{{1}以同样的方式。

我想知道如何通过创建将执行此部分代码的通用抽象 DoubleStep1 来消除此代码重复:

i_right

尝试编译此代码(scala 2.9.2)失败,并显示以下消息:

type mismatch;
 found   : (this.StandardStep2, this.StandardStep2)
 required: (this.UniqueStep2, this.UniqueStep2)
    ((l,r) => new DoubleUniqueStep2(l,r)).tupled(DoubleStepHelper.next_step_args(left,right)(i))
                                                                                            ^

我认为发生这种情况是因为假定next_step返回object DoubleStepHelper { def next_step_args[IL,IR,SL <: StandardStep1[IL],SR <: StandardStep1[IR]](left:SL,right:SR)(i:(IL,IR)) = { val (i_left, i_right) = i val new_left = left.next_step(i_left) val new_right = right.next_step(i_right) (new_left, new_right) } } class DoubleStandardStep1[-IL,-IR](left:StandardStep1[IL], right:StandardStep1[IR]) extends StandardStep1[(IL,IR)] { def next_step(i:(IL,IR)) = { ((l,r) => new DoubleStandardStep2(l,r)).tupled(DoubleStepHelper.next_step_args(left,right)(i)) } } class DoubleStandardStep2(left:StandardStep2, right:StandardStep2) extends StandardStep2 class DoubleUniqueStep1[-IL,-IR](left:UniqueStep1[IL], right:UniqueStep1[IR]) extends UniqueStep1[(IL,IR)] { def next_step(i:(IL,IR)) = { ((l,r) => new DoubleUniqueStep2(l,r)).tupled(DoubleStepHelper.next_step_args(left,right)(i)) } } class DoubleUniqueStep2(left:UniqueStep2, right:UniqueStep2) extends UniqueStep2 值,当我们想要用 DoubleStepHelper.next_step_args 包裹它时,这是不好的。

你能想出解决这个问题的方法吗?如果(StandardStep2, StandardStep2) DoubleUniqueStep2DoubleStepHelper继承自(UniqueStep2, UniqueStep2),如何告诉编译器SL的next_step_args可能会返回SR

一个不错的功能可能是能够将UniqueStep1的结果类型定义为(SL.next_step,SR.next_step),这意味着它的返回类型是从next_step_argsSL中特定函数( next_step )的返回类型。

可以“查看”界限以任何方式解决它吗?

我可以使用 asInstanceOf 强制进行投射,但这看起来很难看。

由于

1 个答案:

答案 0 :(得分:0)

我找到了一个很好的解决方案。我创建了AbstractStep1AbstractDoubleStep1,其中给出了以下步骤的类型作为类型参数。

然后,我可以从下一步为StandardStep2UniqueStep2的情况继承此类。

所以这是代码:

trait AbstractStep1[-I,+S2] {
  def next_step(i:I):S2
}

trait StandardStep1[-I] extends AbstractStep1[I,StandardStep2]

trait StandardStep2

trait UniqueStep1[-I] extends AbstractStep1[I,UniqueStep2] with StandardStep1[I]

trait UniqueStep2 extends StandardStep2

abstract class AbstractDoubleStep1[-IL,-IR,-S2L <: StandardStep2,-S2R <: StandardStep2,+S2](left:AbstractStep1[IL,S2L],right:AbstractStep1[IR,S2R]) extends AbstractStep1[(IL,IR),S2] {
  def wrapper(l:S2L,r:S2R):S2

  def next_step(i:(IL,IR)):S2 = {
    val (i_left, i_right) = i
    val new_left = left.next_step(i_left)
    val new_right = right.next_step(i_right)
    wrapper(new_left, new_right)
  }
}

class DoubleStandardStep1[-IL,-IR](left:StandardStep1[IL], right:StandardStep1[IR]) extends AbstractDoubleStep1[IL,IR,StandardStep2,StandardStep2,DoubleStandardStep2](left,right) {
  def wrapper(l:StandardStep2,r:StandardStep2) = {
    new DoubleStandardStep2(l,r)
  }
}

class DoubleStandardStep2(left:StandardStep2, right:StandardStep2) extends StandardStep2


class DoubleUniqueStep1[-IL,-IR](left:UniqueStep1[IL], right:UniqueStep1[IR]) extends AbstractDoubleStep1[IL,IR,UniqueStep2,UniqueStep2,DoubleUniqueStep2](left,right) {
  def wrapper(l:UniqueStep2,r:UniqueStep2) = {
    new DoubleUniqueStep2(l,r)
  }
}

class DoubleUniqueStep2(left:UniqueStep2, right:UniqueStep2) extends UniqueStep2

我认为也可以将AbstractDoubleStep1转换为 triat 而不是抽象类,这将使它在mixin继承中更有用,但是这对我来说并不重要。