^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
DEVELOPERS' WORKSHOP: One Target Per Invoker Is Not Enough
By Owen Smith -- <orpheus@be.com>
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Recently, the DTS oracle has been peppered with questions
about messaging. One of the questions that popped up was:
"Well, all of this sending of messages to one target is well
and good, but what if I need to send a message to multiple
targets?" This resulted in the rallying cry that I adopted
as the title of this article -- inspired by the BeBox
slogan from a few years ago.

There are several ways to solve this problem, depending on
what your requirements are. One way is to keep a list of
BMessengers around, one for each target, and when you want
to send a message, simply tell each messenger to send the
message for you. Of course, it would be nice to encapsulate
this functionality in a class, so I have:

<ftp://ftp.be.com/pub/samples/application_kit/
MultiInvoker.zip>

This little piece of code implements a class that looks much
like a BInvoker, and like BInvoker, it works well as a mix-
in class. Its interface differs slightly from BInvoker,
however, because instead of a single target, it maintains a
list of targets. Appropriately, when you tell it to Invoke,
it simply runs through the list of targets and sends the
message to each target.

Note that you can either add a target using the standard
BHandler/BLooper pair of parameters, or you can create a
BMessenger dynamically and hand it off to the MultiInvoker
(the MultiInvoker will delete the messenger when it's done).
The great advantage to the latter approach is that, if you
have a specially derived BMessenger (e.g. one that sends
messages to a target across a network), you can simply
toss one of those puppies to a MultiInvoker and it will
Just Work (tm) -- an extra piece of flexibility that
BInvoker doesn't provide for you.

This approach works very well for any Observer patterns in
your code (this terminology comes from "Design Patterns" by
Gamma, Helm, Johnson, and Vlissidies, and remains one of my
all-time favorite books about programming). For example, the
sample code archive for this week contains a simple test app
with several observers. The application creates an Observ-
able object that derives from MultiInvoker. When the time
comes for the observable to broadcast an update, it simply
calls Invoke() with a message that describes its state. The
messaging mechanism inherent in MultiInvoker makes this
approach particularly well-suited for multithreaded appli-
cations.

One limitation to this approach, however, is that the sender
has to know who the targets are. Depending on your situa-
tion, you may want flexibility on the receiver's end about
who receives the message -- for example, if you're sending a
message to a Mediator object, and you want the mediator to
dispatch the message to the appropriate targets. That limi-
tation can easily be overcome as well, by creatively using
BLoopers or BMessageFilters -- but that's a topic for
another time...
