Scala(およびakka)アクターフレームワークの適切な使用法のほとんどの例では、人々はすべてのメッセージを単一の特性から派生させる傾向があります。例えば:
trait Message
object Ping extends Message
object Pong extends Message
ただし、ScalaとAkkaの両方で、メッセージ受信はまったく入力されません。共通の特性を実装する理由はありますか?
これは本当にあなたが達成しようとしていることに依存します。たとえば、私は最近、いくつかのタイプのアクターを持つアクターと、多かれ少なかれルーターのように機能する管理アクターを使用して、小さなアプリケーションを構築しました。これで、作業中のアクターは、、、など、さまざまなメッセージを受け取ることがFoo
できBar
ますBaz
。スーパータイプがなければ、マネージングアクターで次のように書く必要があります。
react {
case x:Foo | x:Bar | x:Baz => worker ! x
}
これは明らかに不必要に冗長です。したがって、この場合、スーパータイプWorkerMessage
はコードを単純化するため、非常に理にかなっています。
react {
case x:WorkerMessage => worker ! x
}
一方、これによりメッセージが作成されFoo
、WorkerActorによって使用される以外の目的にはほとんど使用できなくなります。たとえば、メッセージがある場合は、あちこちで再定義する必要があるため、これはおそらく悪いことです。Bar
Baz
Stop
Init
したがって、メッセージを渡さない(つまり、メッセージを自分で処理する)アクターしかいないことがわかっている場合は、スーパータイプがなくても問題ないと思います。
人々がデフォルトでこれを多かれ少なかれ行う理由は、後でコードを変更した場合、最初にすでに行っているので、後でトレイトを作成する必要がないためだと思います。
個人的には、不必要なオーバーヘッドを常に避けようとしているので、本当に必要でない限り、スーパータイプを定義することはおそらくないでしょう。また、スーパータイプの作成がパフォーマンスに影響を与えるかどうかは本当にわかりませんが、知りたいと思います。
(またはscala.actors
を介して) と Akka ( ) の両方を使用して、着信メッセージのタイプ境界を設定できます。InputChannel[T]
Reactor[T]
TypedActor
ほとんどの例では、メッセージはsealed trait
. これには 2 つの理由があります。
アクターのメッセージ ハンドラー (部分関数) がトレイトを拡張するすべてのメッセージをカバーしていない場合、コンパイラーは警告を生成します。
sealed trait
特性が定義されているソース ファイルでのみ拡張できるため、クライアントは特性を拡張する独自のメッセージを定義できません。
これは必須ではありませんが、OO 設計のものです。アプリケーション ドメイン メッセージに抽象型を使用することをお勧めします。そのため、アプリケーション コードでメッセージを処理するときにポリモーフィズムの利点を得ることができます。
trait Message
object Ping extends Message
objet Pong extends Message
object Stop
たとえば、アプリケーションのどこかで、特定のタイプ (Ping または Pong) に関係なく大量のメッセージを処理する必要がある場合、それらすべてを Message 型のオブジェクトとして扱います。それは理にかなっている?いいえ ?