sme*_*eeb 6 java messaging akka
要在Akka(Java绑定)中实现自己的自定义actor,可以扩展UntypedActor基类.这需要您定义自己的onReceive(...)方法:
@Override
public void onReceive(Object message) {
// TODO
}
Run Code Online (Sandbox Code Playgroud)
手头的问题是确定一种消息处理策略,使actor能够处理多种类型的消息.一种策略是使用反射/类型.这里的问题是:
message参数并阻止我们传递任何动态或有意义的东西空shell类的示例:
public class EmptyShellMessage { }
Run Code Online (Sandbox Code Playgroud)
然后在该onReceive方法中看起来像:
@Override
public void onReceive(Class<?> message) {
if(message.isAssignableFrom(EmptyShellMessage.class)) {
// TODO
} else {
// TODO
}
}
Run Code Online (Sandbox Code Playgroud)
因此,我们不仅创建了一个无用的类,而且由于Object message现在用于确定消息的类/类型,我们不能使用它来包含任何更多的信息,尤其是另一个actor可能的动态/运行时信息想传递它.
有时我会看到这种变化:
@Override
public void onReceive(Object message) {
if(message instanceof FizzEvent) {
// TODO
} else {
// TODO
}
}
Run Code Online (Sandbox Code Playgroud)
但在这里我们使用的instanceof是许多人认为是一个巨大的反模式(只是谷歌" 反对模式的实例 ").
然后我们有枚举:
public enum ActorMessage {
FizzEvent,
BuzzEvent,
FooEvent,
BarEvent
}
Run Code Online (Sandbox Code Playgroud)
现在onReceive看起来像:
@Override
public void onReceive(ActorMessage message) {
if(message.equals(ActorMessage.FizzEvent)) {
// TODO
} else {
// TODO
}
}
Run Code Online (Sandbox Code Playgroud)
这里的问题是我们可能有一个大型的actor系统,需要处理数百甚至数千种不同的事件/消息类型.这个枚举变得很大并且难以维护.它也有与上面的反射策略相同的问题,它阻止我们在actor之间发送任何动态信息.
我能想到的最后一件事是使用字符串:
@Override
public void onReceive(String message) {
if(message.equals("FizzEvent")) {
// TODO
} else {
// TODO
}
}
Run Code Online (Sandbox Code Playgroud)
但我讨厌这个.期.句末.
所以我问:我在这里错过了一些明显的东西,也许是另一种策略?Java/Akka应用程序应该如何处理大量的事件/消息类型,并指定它们在onReceive方法中处理哪一个?
不,你没有遗漏任何东西.我也不是粉丝.在Scala中它更好一点,因为onReceive方法可以被换出来模拟协议的变化状态,它使用的部分函数比if/elseif/else好一点......但它仍然很蹩脚.它在Erlang中更好,这是该模型的起源但是,鉴于akka团队面临的局限性,他们做出了正确的设计选择并做得非常出色.
另一种策略是执行双重调度.因此,将命令传递给actor作为动作,或者在map中查找消息的处理程序.Akka特工基本上是前者,当他们的力量使用时非常好.但总的来说,双重调度只会增加复杂性,因此对于大多数情况,人们只需要习惯标准方法.在java中,这意味着是instanceof还是switch语句.
双重调度(伪代码)的一个示例,此处包含完整性,以帮助理解.作为一种方法,它带有健康警告,所以我重申; 标准方法是标准的原因,并且应该使用99%的时间.
onReceive( msg ) {
msg.doWork()
}
Run Code Online (Sandbox Code Playgroud)
这种方法的问题在于,现在消息需要知道如何处理自己,这很脏; 它会引起紧密耦合并且可能很脆弱.呸.
所以我们可以使用查找处理程序(命令模式样式)
val handlers = Map( "msgid1"->Handler1, "msgid2->Handler2 )
onReceive( msg ) {
val h = handlers(msg.id)
h.doWork( msg )
}
Run Code Online (Sandbox Code Playgroud)
这里的问题是,现在还不清楚命令是什么,并且遵循代码通过涉及跳转更多.但有时候这是值得的.
正如Roland所指出的那样,在传递对演员本身的引用时必须小心.上面的例子并没有违背这个问题,但这很容易诱惑.
| 归档时间: |
|
| 查看次数: |
2074 次 |
| 最近记录: |