我很新于Scala,正在努力适应Scala特定的模式。
目标是分离消息处理和消息生成。有一种基本的协变参数化类型表示消息处理。具体实现可以通过常规mixin或混合底层协议来组合。
要求如下:
1.尽可能简单地扩展 2.为了防止愚蠢的错误而安全
我提供了干净的样例代码(包含定义和使用):
上一个例子没有很好地输入,如预期所示产生了错误:
目标是分离消息处理和消息生成。有一种基本的协变参数化类型表示消息处理。具体实现可以通过常规mixin或混合底层协议来组合。
要求如下:
1.尽可能简单地扩展 2.为了防止愚蠢的错误而安全
我提供了干净的样例代码(包含定义和使用):
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类而不是代数类型。
我几乎实现了我的目标,但遇到了一个大问题:底层JVM的类型擦除。我使用的结构对于Scala来说是非法的,因为我希望参数化的trait可以通过“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
我有什么选择?我不能使用我设计的模式,需要通过可用性找到一个相等的替代品。是否有人可以提供另一种源代码解决方案?是否有scala插件(它们似乎存在于编译器中)或其他方法来将scala参数化类型的后端从Java通用代码更改为类似C ++的代码生成?