Building on Leri, I would think more along the lines of what a tracker might need to do.
I would be inclined to do something like this:
public interface ITracker {
void BeginTracking();
void Track(ITrackerEvent trackerEvent);
void EndTracking();
}
Then all trackers have a sense of when they're starting and when they're finishing. This is important because a tracker may be holding onto resources that shouldn't be held longer than necessary. If a tracker doesn't need to use either BeginTracking
or EndTracking
, the implementation is trivial. A trivial implementation is not a leaky abstraction. A leaky abstraction is one that doesn't work for all implementations.
Now suppose you are flat-out against having two extra methods in each tracker (why?). You could instead have ITrackerEvents that are out of band and cover the semantic meaning of Begin and End. I don't like this. It requires every tracker to have special code to handle out of band events.
You can also have a separate interface
public interface IDemarcatedTracker : ITracker {
void BeginTracking();
void EndTracking();
}
which requires you to have special case code in your calling code to check to see if the ITracker is also an IDemarcatedTracker:
public void BeginTracking(ITracker tracker)
{
IDemarcatedTracker demarcatedTracker = tracker as IDemarcatedTracker;
if (demarcatedTracker != null)
demarcatedTracker.BeginTracking();
}
And not to over blow things too much, but I would also wonder what is supposed to happen when a tracker fails? Just blindly throw an exception? And here is where the abstraction is actually leaky. There is no process for a tracker to let you know that it can't track.
In your case you might want to return a boolean (limited information), an error code (somewhat more information), or an error class/struct. Or you might want to have a standard exception that gets thrown. Or you might want the Begin() method to include a delegate to call when an error happens in tracking.
Flush
to be called. That's the only important question. My guess is, either "on each call", or "every now and then", and a final flush on dispose. – AnnounceFlush()
with garbage collection? I mean, you could callFlush
repeatedly during a socket session with a remote server and the only thing you're intending there is to send the message across the wire to the other machine... – NussFlush
has to be called. My concern is that I don't want the fact I have to Flush (whether occasionally or on application shutdown) to leak through into myITracker
interface. – Rothwell