Implementing public interfaces in protected "mode"
Note: this entry has moved.
Quite often, we create interfaces as a way to allow extensibility in our OO projects. But as you know, all the members of the interface are public. So, if we don't want to polute our objects public members with the implementation of an interface that was intended for extenders and not the regular user, we can simply make the interface implementation explicit, effectively hiding the member from the class public interface:
public interface IExtensible
{
void Extend( object other );
}
public Customer : IExtensible
{
void IExtensible.Extend( object other )
{
// Do something really cool.
}
}
So far so good. Now the Extend
method will no longer appear in
intellisense nor will it be available directly. To use it, it has to be casted
to the IExtensible
interface, but that isn't a problem at all,
since most probably, the feature is intended to be used by a method that
receives a parameter of type IExtensible
anyways.
But now the interface implementation can't be extended by inheritors of Customer
!
A pattern I've seen quite often throughout the .NET Framework to solve this is
doing a double implementation of the method, one private (the explicit
interface implementation) and another protected and virtual, so that inheritors
can effectively override the base class' private interface implementation
behavior:
public class Customer : IExtensible
{
protected virtual void Extend( object other )
{
// Do something really cool, but let inheritors change that.
}
void IExtensible.Extend( object other )
{
// Passthrough to the "real" implementation.
Extend( other );
}
}
What we got now, is a non-poluted public interface for our class, yet inheritors have full access to features that were intended for their use, such as our interface that allows extensibility. If they don't want to inherit our implementations, they can always implement the interface directly, of course:
public class ExtendedCustomer : Customer
{
protected override void Extend( object other )
{
// Stop doing cool things and just do the work.
}
}