Re: OO Principle - reference needed
- From: "H. S. Lahman" <h.lahman@xxxxxxxxxxx>
- Date: Fri, 20 Apr 2007 15:12:25 GMT
Responding to Sanford....
I have a question about setting up collaborations. Let me give a
trivial example. Say an object uses a timer. It doesn't create the
timer itself, rather the timer is passed to it when it is created.
The object that uses the timer stops and starts the timer as it
pleases and consumes "tick" events generated by the timer. My
question is whose responsibility is it to ensure the integrity of the
relationship between the two object?
First, some background to make sure we are on the same page. We have:
| provides timer notifications to
I was thinking of a one-to-one relationship. I think the above describes
It was just an assumption that a Timer could be reused by multiple clients just like an OS timer. That is pretty common in R-T/E or concurrent applications.
To continue with the example, the consumer, i.e. the object that uses
the timer, makes certain assumptions. It assumes that when it starts
the timer, it's not already running. And when it stops the timer no
one else will start it again. In other words, it's in control of the
This is a much broader issue that is related to the fundamental way
the OO paradigm approaches collaborations.
In fact, SomeOBject has no expectations about Timer; its
implementation should not even know that a Timer exists. The whole
point of the OO paradigm is to eliminate the hierarchical
implementation dependencies implicit in the Do This approach of
traditional functional decomposition where the message sender
/expects/ something to be done.
As a result, messages in the OOA/D are supposed to be announcements
(I'm Done) and they are peer-to-peer to avoid hierarchies. To provide
an announcement the object only needs to understand itself and not its
It is the job of the developer to connect the dots of the OO solution
in the OOA/D by mapping announcement messages to objects that care
what is being announced. In UML one does that in an Interaction
Diagram that is at a higher level of abstraction than individual
object methods. So, in theory, one can define collaborations after all
of the object methods have been defined and implemented.
I'm going to expand on my example a bit. Let's say that SomeObject
represents a MIDI file player (I use MIDI as an example because I'm
familiar with it). It needs timer notifications to drive playback of
MIDI data. If the timer is passed to the Player's constructor, the
player can connect to the timer to receive the tick notifications as
well as start and stop the timer whenever it needs to do so. However, if
we set things up so that the Player doesn't know about the Timer, then
we need a way for the periodic ticks generated by the timer to be
delivered to the Player, as well as starting and stopping the timer when
Keeping this as simple as possible, one approach would be to have a Tick
method in the Player's interface. This will need to be called in
response to the timer's Tick event, so an infrastructure is needed to
respond to the timer and pass along the message. Also, the Player needs
to announce when it requires the timer's services. So a typical scenario
could be that a Play method is called on the Player. This causes the
Player to send a message that it is playing (or at least wants to play).
The infrastructure receives this message and fires up the timer. The
timer generates timing messages which are then delivered to the Player
via its Tick method.
I'm going to get a little dirty with some code. This is in C# and uses
anonymous methods to connect the objects together:
Player player = new Player();
Timer timer = new Timer(10); // Raise ticks events every 10ms.
// Playing is an event raised by the Player when the Play method is
// called (assuming the Player is in a idle state, i.e. ready to play).
player.Playing += delegate(object sender, EventArgs e)
// Stopped is an event raised by the Player when the Stop method is
// called (assuming the Player is already playing).
player.Stopped += delegate(object sender, EventArgs e)
// Tick is an event raised periodically by the Timer when it is running.
timer.Tick += delegate(object sender, EventArgs e)
The syntax may seem a little odd if you're not familiar with C#, but
basically this sets up anonymous methods to delegate the events raised
in the player object to call methods in the timer object and vice versa.
In other words, the anonymous methods act as a delivery system for
events raised in one object to be sent via method calls to another
My question is does the mechanism I've used above represent, at least in
spirit, what you mean by "I'm Done" announcements?
(BTW, "Playing" and "Play" may not be the best names here because they
imply that the Player is in fact playing when in reality it won't do
anything until it begins getting tick messages via its Tick method, so
maybe some other names would be more appropriate).
Given this caveat, then the answer is basically Yes. Timer.Start(), timer.Stop(), and player.Tick() are just messages. At the 3GL level that is not clear because a message is the method signature and we name methods by what they do so the message /seems/ to be an imperative.
The key is that the methods that send those messages do not depend on what the response is; they just do their own thing. We could have renamed the messages as:
timer.Start() => ATimerIsRelevant
timer.Stop() => ATimerIsNotRelevant
player.Tick() => TenTimeUnitsHavePassed
In fact, the natural way for this to work is for Player and Timer to both have object state machines to enforce the implied sequencing rules in the transitions. In that case the events would be named something like the above and would be decoupled from the methods through the state transition table.
The beauty of this approach is that Player and Timer are completely
agnoistic to the other's existance. We're free to "connect the dots"
without the objects knowing about each other.
I don't know C# so I don't quite understand anonymous methods. However, it seems to me that the collaboration between a particular Player and a particular Timer is hard-wired in the code.
By implementing and instantiating the relationship orthogonally to the class' semantics I would expect more freedom to reconnect the dots. That is, one can change the Timer/Player assignment without touching anything in either's definition of implementation. One just needs to reassign the value of the referential pointer attribute. IOW, I think there is an implicit assumption in the solution that there is exactly one Timer and one Player.
Getting back to my original concern, based on what you've said, it would
be the responsibility, if I understand correctly, of the one setting up
this collaboration to make sure that the objects play nicely. For
example, during a play session, you wouldn't want the Tick method on the
Player object called indiscriminately by someone else because it could
screw up the timing of the playback. It's up to the one setting up the
collaboration to ensure this doesn't happen.
That is correct. However, if one defines the DbC precondition properly for the Tick method's execution, it should be possible to figure out where the message needs to be generated (i.e., where player.Tick() is called). For example, one clause of that precondition would be that a Timer was available and had been started. When one is used to using state machines, that sort of thing screams for a handshaking protocol that is enforced by the FSM transitions.
Note, though, that this is orthogonal to making sure the right Timer is generating the ticks for the given player (i.e., the correct Timer is available). In this example there seems to be only one Timer generating fixed tick events. In other situations, though, there could be multiple Timers generating tick events at different frequencies for different objects. In that case one does have to be careful about which Timer is connected to which Player and I think a pointer referential attribute is ideally suited to that because it allows the rules of the participation context to be separated from the rules of collaboration (e.g., starting the Timer before getting ticks).
I'm snipping what you said below about DbC, but want you to know that
I've seen you discuss this before and your explanation here further
illuminates the concept. I now have a better understanding.
I'm glad somebody is listening. B-) I think it is sad one doesn't see this discussed in the OO literature outside of R-T/E. It is really a quite general approach for resolving complex dynamic sequencing.
There is nothing wrong with me that could
not be cured by a capful of Drano.
H. S. Lahman
"Model-Based Translation: The Next Step in Agile Development". Email
info@xxxxxxxxxxxxxxxxx for your copy.
Pathfinder is hiring: http://www.pathfindermda.com/about_us/careers_pos3.php.
- Prev by Date: Re: Dependency Management (Was: Mixing P/R philosophy with OO)
- Next by Date: Re: Dependency Management (Was: Mixing P/R philosophy with OO)
- Previous by thread: Re: OO Principle - reference needed
- Next by thread: Re: OO Principle - reference needed