阿卡的战略模式

时间:2015-02-05 10:17:18

标签: scala design-patterns akka

这是我之前提问How do I get around type erasure on Akka receive method

的延续

我有10种类型的事件,它从我需要处理的事件扩展而来。

我想在单独的特征中为每个事件实现业务逻辑,因为混合所有10个事件处理函数将产生数百(如果不是数千)行代码。

我不想为每个事件创建不同的Actor类型。例如:

class Event1Actor extend Actor{
  def receive ={
     case Event1(e) => //event1 Business Logic
   }
}

class Event2Actor extend Actor{
  def receive ={
     case Event2(e) => //event2 Business Logic
   }
}  

和相同的Event3Actor,Event4Actor等......

这样的代码对我来说似乎很难看,因为我需要在每个Actor中实现业务逻辑。

实现10个不同的特征和10个不同的Actor类似乎也是糟糕的设计。

我正在寻找基于设计模式的某种通用解决方案,例如战略模式。

2 个答案:

答案 0 :(得分:2)

case class EventOperation[T <: Event](eventType: T)

class OperationActor extends Actor {

  def receive = {
    case EventOperation(eventType) => eventType.execute
  }

}

trait Event {
 def execute //implement execute in specific event class
}

class Event1 extends Event {/*execute implemented with business logic*/}
class Event2 extends Event {/*execute implemented with business logic*/}

希望这是你正在寻找和帮助的东西,我已经使用这个模式去除了在执行不同类型事件的单个actor下包装所有动作的多余actor。

答案 1 :(得分:1)

你可以尝试这样的事情,它涉及通过基本特征自动组合接收功能。首先是代码:

case class Event1(s:String)
case class Event2(i:Int)
case class Event3(f:Float)

trait EventHandlingActor extends Actor{
  var handlers:List[Receive] = List.empty

  override def preStart = {
    val composedReceive = handlers.foldLeft(receive)((r,h) => r.orElse(h))
    context.become(composedReceive)
  }

  def addHandler(r:Receive) {
    handlers = r :: handlers
  }

  def receive = PartialFunction.empty[Any,Unit]
}

trait Event1Handling{ me:EventHandlingActor =>
  addHandler{
    case Event1(s) => println(s"${self.path.name} handling event1: $s") 
  }
}

trait Event2Handling{ me:EventHandlingActor =>
  addHandler{
    case Event2(i) => println(s"${self.path.name} handling event2: $i") 
  }
}

trait Event3Handling{ me:EventHandlingActor =>
  addHandler{
    case Event3(f) => println(s"${self.path.name} handling event3: $f") 
  }
}

因此,您可以在EventHandlingActor特征中看到我们设置了List类型Receive,可以通过我们堆叠到具体actor中的每个特定处理特征来添加它。然后,您可以看到在单独的特征中定义的每个事件的处理功能的定义,该特征调用addHandler以添加另一个处理功能。在preStart中,对于任何类型的EventHandlingActor impl,接收函数将与receive一起组成起始点(默认为空),然后热插拔接收impl {{1 }}。

现在以几个impl演员为例:

context.become

第一个只处理事件,所以它需要做的就是定义它在适当的特征中处理混合的那些事件。第二个处理一种类型的事件,但也处理一些不是事件的其他消息。此类重写默认的空接收,并提供处理非事件消息的功能。

如果我们像这样测试代码:

class MyEventHandlingActor extends EventHandlingActor 
  with Event1Handling with Event2Handling with Event3Handling

case class SomeOtherMessage(s:String)
class MyOtherEventHandlingActor extends EventHandlingActor with Event1Handling{
  override def receive = {
    case SomeOtherMessage(s) => println(s"otherHandler handling some other message: $s")
  } 
}

然后我们会看到与此类似的输出(由于异步处理消息而导致订单发生变化):

  val system = ActorSystem("test")
  val handler = system.actorOf(Props[MyEventHandlingActor], "handler")

  handler ! Event1("foo")
  handler ! Event2(123)
  handler ! Event3(123.456f)

  val otherHandler = system.actorOf(Props[MyOtherEventHandlingActor], "otherHandler")
  otherHandler ! Event1("bar")
  otherHandler ! SomeOtherMessage("baz")