我正在使用Akka中已建立的代码库,我看到了很多这样的模式:
class Bar(a: A, b: B, c: C) extends Actor {
// body of actor
}
object Bar {
def props(a: A, b: B, c: C) = Props(new Bar(a = a, b = b, c = c)
}
但道具方法感觉像Java中的getter / setter一样难看。有更好的方法吗?
我认为直接创建演员是可能的。
var child = context.actorOf(Props(new Bar(a, b, c))
因为这并不比使用道具的版本复杂得多:
var child = context.actorOf(Bar.Props(a, b, c))
但如果我理解Deprecation of Closures Taking Props上的这篇文章,那么这是不好的做法。相反,他们主张使用:
var child = context.actorOf(Props(classOf[Bar], a, b, c))
但是,当Ryan在下面概述时,这会遇到重构问题吗?
答案 0 :(得分:3)
让它更接近类的主要原因是因为涉及到反射,并且你不希望反射调用遍布你的代码库,因为你的actor的构造函数中的一个更改可能会在运行时破坏事物而你希望堆栈跟踪尽可能接近您的问题(顺便说一下,您似乎没有在示例中使用Actor构造的反射方式)。
修改强>
object MyActor {
def props(param: Int): Props = Props(classOf[MyActor], param)
}
class MyActor(param: Int) extends Actor {
def receive = ...
}
如果您要更改MyActor
的构造函数以接受例如一个额外的参数,如:
class MyActor(param: Int, param2: String) extends Actor { ... }
您的代码编译得很好,但在运行时,反射API将无法找到与Props(classOf[MyActor], param)
的调用匹配的公共构造函数,因此会抛出异常,您将看到堆栈跟踪登录。您希望堆栈跟踪尽可能接近问题的根,因此您可以更快地找到/修复问题。如果每个人都使用props
工厂方法,那么所有堆栈跟踪(如果有的话)引导您的唯一地方就是props
工厂方法的定义。
答案 1 :(得分:3)
除了让Props
创建更接近actor的类之外,它还避免意外关闭actor的this
引用,就像你在另一个actor中使用Props(new MyActor("foo"))
一样。
请参阅most recent reference guide section on Props
:
这也避免了与使用相关的陷阱 Props.apply(...)方法,它采用一个名字参数,因为在一个 伴随对象给定的代码块不会保留对引用的引用 它的封闭范围。
如果你真的不想使用伴侣对象.props
并想在另一个演员中创建Props
,那么你应该使用这个版本的Props
创建者来保证安全:
def apply(clazz: Class[_], args: Any*)
例如:
context.actorOf(Props(classOf[MyActor], "foo"))
明显的缺点是它不提供参数的类型检查。