The problem with object oriented languages is that you often have to wrap up single functions in a class even when there’s no real reason for that class to exist. This is especially true for many ‘service’ classes. For example, for a long time I used to have something like this in most of my projects:
public interface IDateProvider
{
DateTime Now();
}
public class DateProvider : IDateProvider
{
public DateTime Now()
{
return DateTime.Now();
}
}
I would register my DateProvider with Windsor like this:
container.Regisgter(
Component.For<IDateProvider>().ImplementedBy<DateProvider>()
);
Being able to set the current time in unit tests is essential if you’re doing any kind of logic that does date computations, and this served me well. But it’s a lot of boiler plate just to get the current date. It also means that I have to build a mock IDateProvider for my unit tests and set stubs on it – more irritating boiler plate.
But C# is also quite a good functional language and Windsor deals with delegates just as easily as it deals with interfaces. These days I no longer have an IDateProvider, but just a simple delegate:
public delegate DateTime Now();
Which I register like this:
container.Register(
Component.For<Now>().Instance(() => DateTime.Now),
);
Now any component that needs to know the current DateTime value simply has a dependency on the Now delegate:
public class MyComponent
{
private readonly Now now;
public MyComponent(Now now)
{
this.now = now;
}
public void DoSomething()
{
var currentTime = now();
....
}
}
And it’s really easy to stub out for unit tests:
var now = new DateTime(2010, 2, 15);
var myComponent = new MyComponent(() => now);
myComponent.DoSomething();
This is also a great way for providing infrastructure services when your infrastructure isn’t IoC container friendly. How about this:
public delegate string CurrentUser();
...
container.Register(
Component.For<CurrentUser>().Instance(() => HttpContext.Current.User.Identity.Name)
);
In some ways delegates are more flexible than interfaces since you don’t have to declare that a particular lambda or method implements the delegate, so long as the signature matches you’re good.
Indeed, if Windsor did currying we could probably remove most of our service classes and simply write our software as static methods. But that’s another blog post ;)
15 comments:
Interesting idea, however it is best practise not to declare your own delegates- use Func and Action instead.
Hi Richard,
Sorry, I disagree. In this case it's definitely best to declare your own delegates. Of course you could use Func<DateTime> in my example, in fact that's how I started out implementing these things. But say you wanted some other service that provided say, next weekend. Then you'd have two Func<DateTime> and no way to for the container to differentiate between them, because you can only have one instance defined for a single service.
It's also more intention revealing. Better to have a dependency on 'Now' than 'Func<DateTime>', there's no clue with the latter about what that DateTime represents.
Mike,
Didn't think about the container not working- good point. In which case I'd probably stick to using interfaces!
Another option, would be to define a class as follows:
public static class CurrentTime
{
public static Func Now = () => new DateTime();
}
This can then be used as follows:
DateTime now = CurrentTime.Now();
Console.WriteLine(CurrentTime.Now());
CurrentTime.Now = () => new DateTime(2010, 2, 15);
Console.WriteLine(CurrentTime.Now());
Console.ReadLine();
Sorry about the code formatting!
Yet another option would be to use TypeMock isolator or Moles.
Mike,
Sorry, just realised CurrentTime should be:
public static class CurrentTime
{
public static Func Now = () => DateTime.Now;
}
Hi Richard,
Well, the whole point of the post is that interfaces are too much ceremony in many cases. In any case, you can think of delegates as method interfaces, except that they're more flexible in some ways. Like the fact that you don't have to declare a method or lambda as implementing a particular delegate.
I don't like the smell of your static field 'Now', but TBH, I can't see any benefit of using the container over it currently. Of course if I had my 'currying container' then the compositional possibilities would steer me back towards the container based delegate, but you've got me thinking, thanks :)
After a few seconds' more thought... The reason I don't like the static Func<DateTime> field is because there's some vagueness about what its value might be. In my tests I'd have to set it to some stubbed value, but then set it back to it's original value afterwards, which I'd have to be aware of. The test would be expected to know far too much about the mechanics of CurrentTime.Now. By passing a delegate in as a dependency we're being explicit about it's implementation for that particular instance of the client component.
Mike,
Yes the downside to the static Func is the fact it returns the new value after assignment! I was going to add that! I'm sure that could lead to people writing unrepeatable tests if they were not careful! Yikes!
TBH I'm not happy with any of the approaches 100%, but I still think the interface based approach is the most common and pragmatic, and that is the approach I always use in situations like this (until I'm convinced otherwise).
The thing I don't like about this:
container.Register(
Component.For().Instance(() => DateTime.Now),
Is it isn't obvious to call DateTime.Now either- this is even less obvious to me than having to add teardown behaviour to the static Func example I described earlier!
Also how would it work if you are storing container configuration in a config file (I'm not familar with Windsor- but can't imagine this is possible/desirable?)
I've always thought of delegates as being the equivalent to a single method interface (obviously it is not that simple, you can't do Interface.BeginInvoke!) but a useful comparision sometimes.
I look forward to your posts on 'currying containers'.
+1 on currying containers
"I look forward to your posts on 'currying containers'." - Didn't you notice, the last sentence was a link to the post on currying containers :)
Mike,
You talked in a previous post about relying on the container, and making calls to the container as "a bit of an anti-pattern".
Could you possibly elaborate on how that would, or wouldn't, apply in conjunction with this?
Good to learn new tricks. Cheers mate.
Thanks for the kind words Nick.
Yes, scattering calls to container.Resolve() around your code is an anti-pattern.
Here I'm simply pointing out that delegates can define service contracts in the same way as interfaces.
Does this make no sense?
Hi Mike,
Once again a great post. The currying containers was me trying to be funny (obviously it failed!
I'll try to be less humorous in the future!
Richard, sorry, sense of humour bypass :p
I'm so into my currying I forget how stupid it sounds.
No, no it does seem a good way to do things and perfectly explained.
I was just digging a bit deeper, wondering if it gets a bit easy to start relying on the container when maybe you shouldn't?
Nick,
"I was just digging a bit deeper, wondering if it gets a bit easy to start relying on the container when maybe you shouldn't?"
Well of course the whole application structure relies on the container to wire it together. In this example we're registering functions with the container so that they can be passed by the container to components that depend on them.
The magic is that we never see any direct reference to the container in our code (apart from the component registration and single call to resolve buried deep in our framework).
Post a Comment