I was trying NBuilder in my unit test. An excellent library. However, I could not explain the following structure of classes and interfaces.
-
In
FizzWare.NBuildernamespace:ISingleObjectBuilderSingleObjectBuilderExtensions
-
In
FizzWare.NBuilder.Implementation- IObjectBuilder`
ObjectBuilder
-
SingleObjectBuilderExtensionsis simply a wrapper onIObjectBuilder. -
The client code should usually use a class named
Builderwhich has a static method that gives youISingleObjectBuilder. You never need to instantiate any of the classes in client code.
Now, I dont get the point of the SingleObjectBuilderExtensions. Does it give any kind of design benefit? Why not the methods are directly in ISingleObjectBuilder specially when the two interfaces are in same namespace.
ISingleObjectBuilderis an interface; interfaces cannot provide implementation. That would mean that every implementation ofISingleObjectBuilderwould need to provide the implementation.However, in many cases, a method has a pre-defined behaviour, and just needs access to other members of the interface (i.e. just members of
ISingleObjectBuilder), so there is no benefit in making each implementation provide this.Additionally, it is not a good idea to add more members to an existing interface, since that would be a breaking change for all existing implementations.
Extension methods solve both of these issues:
ISingleObjectBuilderHaving it in the same namespace simply makes it convenient. It is a likely bet that any code using
ISingleObjectBuilderalready has ausingdirective importing that namespace; therefore, most code will already see the extension method in the IDE simply by pressing.in the IDE.To add a concrete example, LINQ-to-Objects works on
IEnumerable<T>. There are lots ofIEnumerable<T>implementations. If each of them had to write their ownFirst(...),FirstOrDefault(...),Any(...),Select(...)etc methods, that would be a huge burden – bot would provide no benefit as the implementations would be pretty much identical in most cases. Additionally, fitting this onto the interface retrospectively would have been disastrous.As a side note: per-type versions of a method always take precedence over extension methods, so if (in the case of LINQ-to-Objects) you have a type that implements
IEnumerable<T>(for someT), and that type has a.First()instance method, then:will use your version, not the extension methods.