views:

147

answers:

6

Hi,

I need to create overloads for functions on an existing interface without affecting any components that currently implement or make use of the interface (ideally).

I figure I have a couple of options:

Simplified Original interface:

public interface IServerComponent
{
    bool Add(int a, int b);
}

I can add the new overloaded functions to the interface and force every class that implements the interface to implement the new functions.

public interface IServerComponent
{
    bool Add(int a, int b);
    bool Add(int a, int b, int c);
}

Or I can create a new interface that implements the original interface. Then other classes that make use of the original won't need to change and any new classes can implement the new interface...

public interface IServerComponent2 : IServerComponent
{
    bool Add(int a, int b, int c);
}

What is the best practice is this situation? Are there any other options available?

Thanks

+9  A: 

If the new methods can be expressed in terms of the old methods, you can use extension methods:

// Original interface
public interface IServerComponent 
{ 
  bool Add(int a, int b, int c); 
} 

// New overload
public static class MyServerMethods
{
  public static bool Add(this IServerComponent component, int a, int b)
  {
    return component.Add(a, b, 0);
  }
}

If the methods can't be expressed like that (i.e., they really need to be implemented by the components themselves), then I'd recommend defining a new interface. This approach has maximum backwards compatibility.

Stephen Cleary
+1 for mentioning extension methods
ram
Extension methods will work, but will also have the effect of spreading the functionality of the implementing class across other classes reducing cohesiveness. I see this as a temporary solution at best. In the case where you can't extend the class, because you don't have access to the source, then extension methods make sense. I might do it this way for minor updates to an existing code base, but I'd certainly put it on my list of refactorings for the next major release.
tvanfosson
This totally depends on the design. If you're adding *new functionality*, then I would agree; it belongs on an interface. If you're adding *overloads* (e.g., almost identical functionality, always expressable in terms of other functionality), then I disagree. In this case, extension methods permit *orthogonality*, reducing code duplication. [Joe Duffy](http://www.bluebytesoftware.com/blog/2010/02/10/ExtensionMethodsAsDefaultInterfaceMethodImplementations.aspx) has a good blog post on the subject.
Stephen Cleary
@Stephen - very interesting! However, the virtual dispatch issues give me the willies. I don't think C# supports this well enough to use in all but the simplest projects - it just promotes code entropy too much (and threatens to reduce cohesion, though definitely not in simple cases such as the one we're considering.)
Jeff Sternal
@Jeff: Joe Duffy's post takes it farther than C# really supports (I have [a blog post that delves into this as well](http://nitoprograms.blogspot.com/2010/01/extension-based-types.html)). C++ supports full "static polymorphism" because it has templates; C# is still lacking in this regard. However, *orthogonality* is still possible and important. Does it really reduce cohesion? I say "nay". Modern APIs (LINQ, TPL, Rx) all define a "minimal interface" to be implemented, and provide the real power of the library as extension methods. We are slowly re-inventing the orthogonal design of the C++ STL
Stephen Cleary
@Stephen - there are cases where adding functionality via extension methods increases understandability (see HtmlHelper extensions in MVC, for example), but in the general case I'd prefer not to have to navigate to other classes to understand a method on the class I'm working with. I voted the answer up precisely because of the specific use case you reference and your comment about new functionality, but I'd still refactor in a major release to put all the code for the new class in one place.
tvanfosson
@tvanfosson: It does depend on the programmer's background. I am a heavy C++ STL user from way back, so to me extension methods are just natural. If C# had full static polymorphism (or another solution for the virtual dispatch problem), then I would say extension methods would be the best solution. I do see where you're coming from, though; the STL caused a fair amount of controversy because it wasn't classical (inheritance-based) OOP. Classical OOP programmers would strive to place everything on the interface. The STL does use OOP concepts, just in different ways; it's an evolution of design.
Stephen Cleary
+4  A: 

If your IServerComponent interface hasn't shipped yet or is an internal interface that is only implemented by your own classes, and the new interface members make sense for all existing classes implementing the interface, change the existing interface.

Otherwise, create an IServerComponent2 interface that extends IServerComponent. IIRC this is what the Framework Design Guidelines recommend. An example of this can be found in the .NET Framework in form of the X509Certificate2 class.

However, if the new members can be implemented in terms of the original members, you could also use extension methods:

public interface IServerComponent
{
    bool Add(int a, int b);
}

public static class ServerComponentExtensions
{
    public static bool Add(this IServerComponent isc, int a, int b, int c)
    {
        return isc.Add(a, b) && isc.Add(b, c) && isc.Add(c, a);
    }
}
dtb
A: 

It depends on the context - if there are many classes that implement the original interface, or if its published, then the only practical way is to introduce the new one. On the other hand having only one interface is much cleaner in the long run, so I would say refactor the existing one if you can afford it.

Grzenio
A: 

If you don't need or want to change the classes (now or in the future) that already implement the old interface, you should just create a second interface. However, it feels more like a hack, and might give you less intuitive code.

Plus, postponing a refactoring is never a good idea in my experience. So if you suspect you will need to implement the interface later, you might as well just alter the existing one and spare yourself some headache. It definately the cleaner way to do it.

Nubsis
A: 

I think maintaining a single interface is easier but the second approach with 2 interface is better because not every class needs to implement bool Add(int a, int b, int c);

afsharm
A: 

I realize your example is contrived but I want to give you a contrived answer that is different from what you are expressing so that maybe you can think about it in a different way. Instead of having your interface method operate on something concrete it might make sense to it instead work on something abstract.

For example

public interface IAddableThings
{
  int a;
  int b;
}

public interface IOtherAddableThings : IAddableThings
{
  int a;
  int b;
}

public interface IServerComponent
{
    bool Add(IAddableThings things);
}

If this really is an Add then I think this makes a lot more sense, but if it is really more like Calculate(), you would then want to move some or all of that methods operation down to the IAddableThings objects.

public interface IAddableThings
{
  int a;
  int b;
  bool CalculateMe();
}
Flory