Not surprisingly the Producer/Consumer relationship is the single most important concept in messaging. Let's take a look at those interfaces and how they work. The first we will look at is the interface that an object must meet in order to consume a message.
public interface IConsume<T>
{
void Consume(T message);
}
Next we will need something that can produce a message so we can hook up the consumer to a producer (generally used in a pipeline not for domain objects, domain objects tend to call a message publisher to act for them).
public interface IPublisher
{
void Publish<T>(T message);
}
public interface IProduce<T>
{
void AttachConsumer(IConsume<T> consumer);
}
One important fact to note is that most objects who are producers will only ever have one consumer. So AttachConsumer for most objects will throw an exception (or replace) any time that it already has a consumer and we connect another consumer to that producer (there are some notable exceptions to this rule in the framework that we will discuss later). The reason that we do this is separation of concerns. The producer does not need to know whether there is one or many consumers connected to it.
I think now is a great time to mention that in terms of bringing my domain to messaging these interfaces are the main leak of messaging into the domain. All of the infrastructure etc outside of my domain stays completely outside of my domain. This non-leakage of the infrastructure into our domain is a key concept as we will see shortly when we Remove Infrastructure Out Of Domain and rid ourselves of those pesky nouns inserted by our infrastructure.
One of the great parts of alt.net seattle was the chance to talk with many developers and bounce ideas off of them (ask Dave Laribee I am an "Idea Bouncer"). One of these idea bouncing sessions was with Chris Patterson and Dru Sellers who are working on (and doing a great job I should add) a light weight ESB they call MassTransit. I discussed with them my Producer/Consumer relationships that were quite different that what they were using.
Last night Chris came back to me with a question of whether it was explicit enough in the contract that in a request/response style message which request matched up with which response. While my "first step" in teaching someone messaging is to say "stop thinking request response" these messages can happen fairly often (though not in a synchronous fashion). What is even more likely to have happen is you have an object in a state who when it receives a message "Responds with" no a reply to the client but another routed message itself (see controller example in Mocks are a Code Smell) ... In going through this conversation I started thinking back to DDD and "Intent Revealing Interfaces".
What if I could create an interface that was essentially the same thing but did a better job at revealing my intent of using both of these messages in a "triggered" way.
class RespondsTo<T>
{
public interface With<V> : IConsume<T>, IProduce<V>
{
}
}
important note: I would NOT use this interface for request/response style messaging ... there are better ways of handling this... the domain object still dispatches!
This allows me as a user of this class to realize not only that it produces and consumes a message but that the two messages are in fact linked (when/if they are). Consider the following two examples.
class FooHandler : IConsume<Foo>, IProduce<Bar>
class FooHandler : RespondsTo<Foo>.With<Bar>
The second example here although it simply implements the same two interfaces gives me a lot more easily discoverable information about how that relationship interacts. A more "appropriate" example might be from the controller example
class ATMController : RespondsTo<CardInsertedMessage>.With<RequestAuthenticationMessage>
Take this new interface with a grain of salt as I have not spent a good deal of time playing with it yet (I prefer to re-dispatch generally and not have the producer interface on the object itself) but it would seem to be at the outset quite useful (as well as more intention revealing).
Posted
Fri, Apr 25 2008 1:58 AM
by
Greg