This is really nothing new, but I don't think I've explicitly stated this before: It makes a lot of sense to view delegates as anonymous one-method interfaces.
Many people liken delegates to function pointers. While that's probably correct (I wouldn't really know), it's not a very object-oriented view to take – at least not when we are dealing with managed code. To me, it makes more sense to view delegates as anonymous one-method interfaces.
Lets consider a simple example. As always, we have the ubiquitous MyClass with its DoStuff method. In this example, DoStuff takes as input an abstraction that takes a string as input and returns an integer – let's imagine that this is some kind of Strategy (notice the capital S – I'm talking about the design pattern, here).
In traditional object-oriented design, we could solve this by introducing the IMyInterface type:
public interface IMyInterface
{
int DoIt(string message);
}
The implementation of DoStuff is simply:
public string DoStuff(IMyInterface strategy)
return strategy.DoIt("Ploeh").ToString();
Hardly rocket science…
However, defining a completely new interface just to do this is not really necessary, since we could just as well have implemented DoStuff with a Func<string, int>:
public string DoStuff(Func<string, int> strategy)
return strategy("Ploeh").ToString();
This not only frees us from defining a new interface, but also from implementing that interface to use the DoStuff method. Instead, we can simply pass a lambda expression:
string result = sut.DoStuff(s => s.Count());
What's most amazing is that RhinoMocks understands and treats delegates just like other abstract types, so that we can write the following to treat it as a mock:
// Fixture setup
Func<string, int> mock =
MockRepository.GenerateMock<Func<string, int>>();
mock.Expect(f => f("Ploeh")).Return(42);
var sut = new MyClass();
// Exercise system
string result = sut.DoStuff(mock);
// Verify outcome
mock.VerifyAllExpectations();
// Teardown
Whenever possible, I prefer to model my APIs with delegates instead of one-method interfaces, since it gives me greater flexibility and less infrastructure code.
Obviously, this technique only works as long as you only need to abstract a single method. As soon as your abstraction needs a second method, you will need to introduce a proper interface or, preferably, an abstract base class.
Remember Me
a@href@title, b, em, i, strike, strong
Page rendered at Saturday, February 04, 2012 10:14:24 PM (Romance Standard Time, UTC+01:00)
Disclaimer The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.