【问题标题】:Composing trait behavior in Scala in an Akka receive method在 Akka 接收方法中组合 Scala 中的特征行为
【发布时间】:2012-01-30 16:09:32
【问题描述】:

考虑这两个特征:

trait Poked extends Actor {
  override def receive = {
    case Poke(port, x) => ReceivePoke(port, x)
  }

  def ReceivePoke(port: String, x: Any)
}

trait Peeked extends Actor {
  override def receive = {
    case Peek(port) => ReceivePeek(port)
  }

  def ReceivePeek(port: String)
}

现在考虑我可以创建一个实现这两个特征的新 Actor:

val peekedpoked = actorRef(new Actor extends Poked with Peeked)

如何编写接收处理程序?即,接收者应该类似于以下代码,尽管是“自动生成的”(即所有特征都应该组合):

def receive = (Poked.receive: Receive) orElse (Peeked.receive: Receive) orElse ...

【问题讨论】:

    标签: scala composition akka


    【解决方案1】:

    您可以使用super[T] 来引用特定超类/特征的成员。

    例如:

    trait IntActor extends Actor {
        def receive = {
            case i: Int => println("Int!")
        }
    }
    
    trait StringActor extends Actor {
        def receive = {
            case s: String => println("String!")
        }
    }
    
    class IntOrString extends Actor with IntActor with StringActor {
        override def receive = super[IntActor].receive orElse super[StringActor].receive
    }
    
    val a = actorOf[IntOrString].start
    a ! 5 //prints Int!
    a ! "Hello" //prints String!
    

    编辑:

    针对 Hugo 的评论,这里有一个解决方案,它允许您组合 mixin,而无需手动将它们的接收连接在一起。本质上,它涉及一个带有可变List[Receive] 的基本特征,并且每个混合特征调用一个方法来将自己的接收添加到列表中。

    trait ComposableActor extends Actor {
      private var receives: List[Receive] = List()
      protected def registerReceive(receive: Receive) {
        receives = receive :: receives
      }
    
      def receive = receives reduce {_ orElse _}
    }
    
    trait IntActor extends ComposableActor {
      registerReceive {
        case i: Int => println("Int!")
      }
    }
    
    trait StringActor extends ComposableActor {
      registerReceive {
        case s: String => println("String!")
      }
    }
    
    val a = actorOf(new ComposableActor with IntActor with StringActor).start
    a ! 5 //prints Int!
    a ! "test" //prints String!
    

    唯一要记住的是接收的顺序不应该很重要,因为您将无法轻松预测哪个是链中的第一个,尽管您可以通过使用可变哈希图来解决这个问题而不是列表。

    【讨论】:

    • 这很有趣,谢谢 :-) 但它假定 IntOrString 类型既是 Int 又是 String 的预先存在,并且 IntOrString 知道它应该组成那些(如果我'正在构建一个框架,其他可能会忽略)。难道不能让 IntActor 和 StringActor trait 自动组合吗?
    • 顺序是由混合特征的线性化给出的,因此是“可预测的”;-) 并且使用前置匹配后续特征的覆盖。较早的,所以我认为您的解决方案非常好!
    • 完美展示你的scala-fu! :-)
    【解决方案2】:

    您可以在基本 Actor 类中使用空接收,并在其定义中使用链接收。 Akka 2.0-M2 示例:

    import akka.actor.Actor
    import akka.actor.Props
    import akka.event.Logging
    import akka.actor.ActorSystem
    
    class Logger extends Actor {
      val log = Logging(context.system, this)
    
      override def receive = new Receive {
        def apply(any: Any) = {}
        def isDefinedAt(any: Any) = false
      }
    }
    
    trait Errors extends Logger {
      override def receive = super.receive orElse {
        case "error" => log.info("received error")
      }
    }
    
    trait Warns extends Logger {
      override def receive = super.receive orElse {
        case "warn" => log.info("received warn")
      }
    }
    
    object Main extends App {
      val system = ActorSystem("mysystem")
      val actor = system.actorOf(Props(new Logger with Errors with Warns), name = "logger")
      actor ! "error"
      actor ! "warn"
    }
    

    【讨论】:

      猜你喜欢
      • 2016-03-07
      • 1970-01-01
      • 2010-11-08
      • 2016-11-26
      • 2011-10-21
      • 2016-07-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多