Based on Leri, I would think more about what the tracker can 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 start and when they finish. This is important because the tracker can hold resources that should not be held longer than necessary. If the tracker does not need to use either BeginTracking
or EndTracking
, the implementation is trivial. The trivial implementation is not an leaky abstraction. A flowing abstraction is one that does not work for all implementations.
Now suppose you are flat against two additional methods in each tracker (why?). Instead, you could have ITrackerEvents that are out of range and encompass the semantic meaning of Begin and End. I do not like it. This requires that each tracker has a special code to handle out-of-band events.
You may also have a separate interface.
public interface IDemarcatedTracker : ITracker { void BeginTracking(); void EndTracking(); }
which requires that you have a special code code in the call code to check if ITracker is also an IDemarcatedTracker:
public void BeginTracking(ITracker tracker) { IDemarcatedTracker demarcatedTracker = tracker as IDemarcatedTracker; if (demarcatedTracker != null) demarcatedTracker.BeginTracking(); }
And so as not to overdo it too much, but I also wonder what should happen when the tracker fails? Just blindly throw an exception? And here the abstraction actually proceeds. The tracker does not know that he cannot track.
In your case, you may want to return a logical (limited information), error code (a bit more information) or an error class / struct. Or you might want to get a standard exception. Or you might want the Begin () method to include a delegate to call when a tracking error occurs.
source share