Delegates Are Anonymous Interfaces by Mark Seemann
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.
Comments
We shouldn't believe that delegates are unlike a function pointer just because the latter is not object-oriented. The shoe ... fits. Furthermore, I would argue that an anonymous one-method interfaces is not a first-class object-oriented concept; we can describe it with words, but I doubt that you will find any of the non-.NET literature talking about such a thing. Well ... I will grant that mention might be made under a description of the command pattern.
"Obviously, this technique only works as long as you only need to abstract a single method."
Yes. Then we are in trouble and we didn't even swim that far from shore.
What was the problem? We focussed too much on a method and we ignored the interface. An interface defines the contract of which the method is only a part. The contract is identified by the name of the interface. There is no contract defined by method signatures. "Takes an int and a double and returns a string" doesn't mean anything.
In summary, focussing on the method is every bit as dirty as ... function pointers.
Sincerely,
jonnie savell