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.NBuilder
namespace:
ISingleObjectBuilder
SingleObjectBuilderExtensions
In FizzWare.NBuilder.Implementation
ObjectBuilder
SingleObjectBuilderExtensions
is simply a wrapper on IObjectBuilder
.
The client code should usually use a class named Builder
which has a static method that gives you ISingleObjectBuilder
. 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.
ISingleObjectBuilder
is an interface; interfaces cannot provide implementation. That would mean that every implementation of ISingleObjectBuilder
would 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:
ISingleObjectBuilder
Having it in the same namespace simply makes it convenient. It is a likely bet that any code using ISingleObjectBuilder
already has a using
directive 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 of IEnumerable<T>
implementations. If each of them had to write their own First(...)
, 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 some T
), and that type has a .First()
instance method, then:
YourType foo = ...
var first = foo.First();
will use your version, not the extension methods.