Archive for May 2010
Last time I wrote some GUI code with time dependencies (like refresh data every 10 seconds), I used to extract the timer into an interface with an event and inject that dependency in the presenter/controller/view model. That way the UI logic is kept testable because I can swap the dependency with a test double which triggers the event manually.
Now I think I have a more elegant solution – an Observable from the Reactive Extensions Framework. Take a look at the ViewModel:
1 public class SomeViewModel
3 public SomeViewModel(IObservable<Unit> timer)
5 timer.Subscribe(x => UpdateUI());
8 private void UpdateUI()
Thanks to the generic IObservable<> I can spare an interface. And this is the dependency injection code (no DI-Container in use for simplicity):
1 var timer = Observable
3 .Select(x => new Unit())
6 var model = new SomeViewModel(timer);
The Interval method creates an infinite sequence of events triggered every 10 seconds (line 2). The generated sequence is typed as IObservable<long>, so I need to convert it to a “typeless” IObservale<Unit> in line 3. Unit type comes from functional languages and is supposed to be a typed void. Last thing to do is to tell Rx Framework to raise events on the GUI thread with ObserveOnDispatcher (there is an overloaded ObserveOn method as well). By default events are raised on a thread pool’s thread.
And here is the code to put in a test:
1 var fake = new Subject<Unit>();
3 var model = new SomeViewModel(fake);
5 fake.Publish(new Unit());
Very simple as well. Subject is a very useful generic class which implements both the IObservable<> and IObserver<>, so you can pass an instance of Subject to a method expecting IObservable<> and then Publish into that sequence thanks to the IObserver<> implementation.
So, if think to write an interface with an event, that you want to pass somewhere as a dependency, think again. Maybe the generic IObservable<> interface will do the trick much simpler. Moreover, client code can leverage the full API of Rx provided through extension methods to IObservable<>, so that the client can for example throttle events or combine them in many different ways. Rx is very powerful.
As the next step I’m thinking of abstracting a clock as IEnumerable<DateTime> instead of writing a custom IClock interface or using a global variable like MyTime.Now or much worse DateTime.Now.
What do you think about time and timer dependencies?