设计模式 – 具有相同参数化类型的Scala mixins

我对
scala很新,并且正在寻求适应scala特定模式.

目标是分离消息处理和消息生成.存在表示消息处理的基本协变参数化类型.具体实现可以通过常规mixin或通过混合底层协议来进行.

要求是:

>尽可能扩展为simaple
>保持类型安全以防止愚蠢的错误

我带来了干净的示例代码(包含定义和使用):

trait Protocol

trait Handler [+proto <: Protocol] {
  def handle : PartialFunction[Protocol,Unit] 
  /* can not name the actual protocol type since handler for a subtype also fully supports handling supertype
besides any message extends other subtype ot the supertype since the scala use matching with case classes
and these algebraic type realization is seemed excluded from strait scala type system
  */
}

/*
==============
using scenario
==============
*/

trait SumMsg extends Protocol
case class Sum(op : Int) extends SumMsg
case class Sub(op : Int) extends SumMsg

trait ProdMsg extends Protocol
case class Mul(op : Int) extends ProdMsg
case class Diff(op : Int) extends ProdMsg {
  require (0 != op, "Division by zero is not permited")
}

/* stackable traites */
trait NullHandler {
  def handle : PartialFunction[Protocol,Unit] = { case _ => {} }
}

trait SumHandler extends Handler [SumMsg] with NullHandler{
  var store : Int
  abstract override def handle : PartialFunction[Protocol,Unit] = ({
case Sum(op) => { this.store += op}
case Sub(op) => { this.store -= op}
  }: PartialFunction[Protocol,Unit]) orElse super.handle
}

trait MulHandler extends Handler [ProdMsg] with NullHandler{
  var store : Int
  abstract override def handle : PartialFunction[Protocol,Unit] = ({
case Mul(op) => {this.store *= op}
case Diff(op) => {this.store /= op}
  }: PartialFunction[Protocol,Unit]) orElse super.handle
}

/* concrete classes */
class SumAccum (var store: Int) extends SumHandler

class MulAccum (var store: Int) extends MulHandler

class ArithmAccum (var store: Int) extends SumHandler with MulHandler

/* producers */
class ProduceSums (val accum : Handler [SumMsg]) {
  var state : Boolean = true
  def touch() = if (this.state)
{
  this.state = false
  this.accum.handle(Sum(2))
} else {
  this.state = true
  this.accum.handle(Sub(1))
}
}

class ProduceProds (val accum : Handler [ProdMsg]) {
  var state : Boolean = true
  def touch() = if (this.state)
{
  this.state = false
  this.accum.handle(Mul(2))
} else {
  this.state = true
  this.accum.handle(Diff(2))
}
}

/* tying together via cake pattern */
trait ProtocolComp {
  type Proto <: Protocol
}

trait ProducerComp { this: ProtocolComp =>
  type ProducerT <: {def touch()}
  def getProducer(accum : Handler[Proto]) : ProducerT
}

trait HandlerComp { this: ProtocolComp =>
  type HandlerT <: Handler[Proto]
  def getHandler(store:Int) : HandlerT
}

trait AppComp extends ProtocolComp with ProducerComp with HandlerComp {
  val initStore = 1
  def test() {
val handler = getHandler(initStore)
val producer = getProducer(handler)
producer.touch()
  }
}

/* different examples of compositions */

/* correct usage */

object One extends AppComp{
  override type Proto = SumMsg
  override type ProducerT = ProduceSums
  override type HandlerT = SumAccum
  override def getProducer(accum : Handler[Proto]) = new ProduceSums(accum)
  override def getHandler(store : Int) = new SumAccum(store)
}

object Two extends AppComp{
  override type Proto = SumMsg
  override type ProducerT = ProduceSums
  override type HandlerT = ArithmAccum
  override def getProducer(accum : Handler[Proto]) = new ProduceSums(accum)
  override def getHandler(store : Int) = new ArithmAccum(store)
}

object Three extends AppComp{
  override type Proto = SumMsg with ProdMsg
  override type ProducerT = ProduceSums
  override type HandlerT = ArithmAccum
  override def getProducer(accum : Handler[Proto]) = new ProduceSums(accum)
  override def getHandler(store : Int) = new ArithmAccum(store)
}

/* incorrect usage
static type checking protects from some kind of logic errors
*/

object Four extends AppComp{
  override type Proto = SumMsg
  override type ProducerT = ProduceProds
  override type HandlerT = SumAccum
  override def getProducer(accum : Handler[Proto]) = new ProduceProds(accum)
  override def getHandler(store : Int) = new SumAccum(store)
}

最后一个示例没有很好的类型,并按预期给出错误:

mixed.scala:140: error: type mismatch;
found   : Handler[Four.Proto]
required: Handler[ProdMsg]
  override def getProducer(accum : Handler[Proto]) = new ProduceProds(accum)

我已经构建了一个灵活的系统,简单的组合和扩展,但尽可能使用scala的case类而不是alegraic类型

我几乎实现了我的目标,但遇到了一个很大的scala错误:类型擦除底层的jvm.我使用的结构对于scala是非法的,因为我希望参数化特征可以使用“with”子句进行扩展.

编译抱怨

mixed.scala:53: error: illegal inheritance;
class ArithmAccum inherits different type instances of trait Handler:
Handler[ProdMsg] and Handler[SumMsg]
class ArithmAccum (var store: Int) extends SumHandler with MulHandler

我有什么选择?我无法使用我设计的模式,需要通过可用性找到相同的替代品.可能anoyone建议替代源代码解决方案?是否存在scala插件(它们似乎存在于编译器中)或另一种将scala参数化类型的后端从java泛型更改为类似代码生成的方法?

最佳答案 您的问题不是JVM的类型擦除,而是Scala使用线性化来解析继承.

从Handler中删除类型参数[proto<:Protocol].无论如何,它不被handle方法使用.那么你的非法继承错误就会消失.

点赞