Here is a slide for a talk I gave a couple of years ago that shows an actor’s relationships, as see them:
My notes from the Powerpoint slide:
Processes (or “Actors) respond to commands from, and make information available to, higher calling code. But do not explicitly require information messages to go anywhere. Calling code initiates information messages by request-reply or publish-subscribe mechanisms. Calling code can direct information messages to third parties, or to multiple parties.
In this diagram, none of the three actors “know†about their calling code. The main “Process†actor knows about the two sub-actors, but not about the code that is calling it. One sub-actor is sending a message to the other, but neither sub-actor knows the other exists. It is the main actor that is directing one sub-actor to message the other, which is why the diagram places a dashed line that include the sub-actor communication as being “part†of the main actor.
If this seems strange, let me try and list the benefits of having an actor not know anything about or explicitly depend on it’s calling code:
1) Lower-level actors are simpler; one doesn’t have to understand the higher level code while debugging the lower level actors. Often, low-level actors can run by themselves for testing, or run from a simple test harass.
2) Lower-level actors are more cohesive, modular, and reusable, as they aren’t coupled into the higher-level design. One can re-architect the high-level design without redoing all the sub-components.
3) Actor interactions can often be understood by only looking at one block diagram, the caller’s, as this is where all the interactions are specified. One can know, for sure, what messages one subactor can send to who, without needing to dive into that subactor’s code, because it can only send the notifications the calling code has registered for. This greatly aids debugging.
4) Because sub-actors do not require anything from their caller, and the caller sets up direct communication between subactors, the calling actor is free to use synchronous, wait-for-reply messaging with the subactors.
Number (4) is actually very valuable, because synchronous interaction is simpler than asynchronous, and complex initialization, shutdown, or reconfigurations of the actor system are much easier with synchronous interactions. Having the calling actor not itself participate in the asynchronous message flow between subactors means that it is fully free to setup and shutdown that flow.