Permalink
Browse files

=doc #3886 improved example of PartialFunction.orElse composition

Changed orElse composition example to better highlight it's
possibilities. This is a follow up PR based on a discussion on
akka-user: https://groups.google.com/forum/#!topic/akka-user/vVUZPMeJmzw
  • Loading branch information...
1 parent 90133e2 commit b7dd2a6af581a9edd28dff718135dcb1cd39f15f @ktoso ktoso committed Feb 19, 2014
Showing with 45 additions and 17 deletions.
  1. +10 −3 akka-docs/rst/scala/actors.rst
  2. +35 −14 akka-docs/rst/scala/code/docs/actor/ActorDocSpec.scala
@@ -890,12 +890,19 @@ supervisor’s decision the actor is resumed (as if nothing happened), restarted
Extending Actors using PartialFunction chaining
===============================================
-A bit advanced but very useful way of defining a base message handler and then
-extend that, either through inheritance or delegation, is to use
-``PartialFunction.orElse`` chaining.
+Sometimes it can be useful to share common behavior among a few actors, or compose one actor's behavior from multiple smaller functions.
+This is is possible because an actor's :meth:`receive` method returns an ``Actor.Receive``, which is a type alias for ``PartialFunction[Any,Unit]``,
+and partial functions can be chained together using the ``PartialFunction#orElse`` method. You can chain as many functions you need,
+however you should keep in mind that "first match" wins - which may be important when combining functions that both can handle the same type of message.
+
+For example, imagine you have a set of actors which are either ``Producers`` or ``Consumers``, yet sometimes it makes sense to
+have an actor share both behaviors. This can be easily achieved without having to duplicate code by extracting the behaviors to
+traits and implementing the actor's :meth:`receive` as combination of these partial functions.
.. includecode:: code/docs/actor/ActorDocSpec.scala#receive-orElse
+Instead of inheritance the same pattern can be applied via composition - one would simply compose the receive method using partial functions from delegates.
+
Initialization patterns
=======================
@@ -13,13 +13,12 @@ import akka.event.Logging
//#imports1
import scala.concurrent.Future
-import akka.actor.{ ActorRef, ActorSystem, PoisonPill, Terminated }
+import akka.actor.{ ActorRef, ActorSystem, PoisonPill, Terminated, ActorLogging }
import org.scalatest.{ BeforeAndAfterAll, WordSpec }
import org.scalatest.Matchers
import akka.testkit._
import akka.util._
import scala.concurrent.duration._
-import akka.actor.Actor.Receive
import scala.concurrent.Await
//#my-actor
@@ -197,25 +196,47 @@ object SwapperApp extends App {
//#receive-orElse
-abstract class GenericActor extends Actor {
- // to be defined in subclassing actor
- def specificMessageHandler: Receive
+trait ProducerBehavior {
+ this: Actor =>
- // generic message handler
- def genericMessageHandler: Receive = {
- case event => printf("generic: %s\n", event)
+ val producerBehavior: Receive = {
+ case GiveMeThings =>
+ sender() ! Give("thing")
}
-
- def receive = specificMessageHandler orElse genericMessageHandler
}
-class SpecificActor extends GenericActor {
- def specificMessageHandler = {
- case event: MyMsg => printf("specific: %s\n", event.subject)
+trait ConsumerBehavior {
+ this: Actor with ActorLogging =>
+
+ val consumerBehavior: Receive = {
+ case ref: ActorRef =>
+ ref ! GiveMeThings
+
+ case Give(thing) =>
+ log.info("Got a thing! It's {}", thing)
}
}
-case class MyMsg(subject: String)
+
+class Producer extends Actor with ProducerBehavior {
+ def receive = producerBehavior
+}
+
+class Consumer extends Actor with ActorLogging with ConsumerBehavior {
+ def receive = consumerBehavior
+}
+
+
+class ProducerConsumer extends Actor with ActorLogging
+ with ProducerBehavior with ConsumerBehavior {
+
+ def receive = producerBehavior orElse consumerBehavior
+}
+
+// protocol
+case object GiveMeThings
+case class Give(thing: Any)
+
//#receive-orElse
class ActorDocSpec extends AkkaSpec(Map("akka.loglevel" -> "INFO")) {

0 comments on commit b7dd2a6

Please sign in to comment.