A common unit testing pattern, part 3

And this time I’m going to drift into theory-land for a bit, and I’m not particularly fond of theory-land.  I prefer "getting-stuff-done-land," which is quite often located on another continent.

Conceptually, objects are these things that sit in space and receive and spit out messages.  And if we look at our User class in that way, it kind of makes sense.  We define the behavior of the User object as receiving a message to set its name, and when it does so, it should then emit a message that it should be saved.

And this is a pretty convenient way to think of objects.  It also isn’t modeled well by most object-oriented languages.

C++-derived languages handle relationships of "is-a" and "has-a" types very well.  But, what we really want here is a "talks-to-a" relationship.  There’s no real first-class way to do that.

Also, they handle incoming messages very well, by means of the public interface of an object.  But, outgoing messages are a little tougher.  Sure, you can do all sorts of things with message receivers and emitters, but realistically, people are going to use the built-in constructs of the language.  So, if we want to model objects as message receivers (easy) and emitters (not easy), we should do it in as basic a way as possible.

And now we get back to "getting-stuff-done-land."  Looking at our User class from the past two entries, we can look at the interface we define as the outgoing messages that the object can emit.  Viewed in that way, it makes sense that the object would own that interface - who else would?  And why would an outgoing message from a user know anything about a database?

There’s other ways to model an outgoing message, and they all pretty much boil down to function pointers.

First, you can use virtual protected methods to define messages, and then override them in derived classes to translate them to the incoming messages that are desired by another component/object.  This method has the advantages of looking more traditional, but the disadvantage of not being able to mix-and-match receivers at runtime.

Secondly, you can use events and delegates.  Combined with lambda expressions in C# 3, this can be an effective way to define outgoing messages.  It has the advantage of not requiring additional classes, but the disadvantage is that you have to hook up each event individually.  Also, events can provide multiple dispatch, but that can become wonky if you want to remove individual anonymous delegates, so I’m counting that as a neutral.