2

I'm writing an app it needs to have generic registration step item. It needs to be able to do some specific things (I use interface for that) and it needs to be a visual element (of Xamarin. It doesn't really matter, though), say VisualElement (I use abstract class for that). This is how it all looks like:

public interface IRegistrationStep
{
    Task<bool> Validate();
    void Minimize();
    void Maximize();
}

public abstract class RegistrationStep : ContentView, IRegistrationStep
{
    public abstract Task<bool> Validate();
    public abstract void Minimize();
    public abstract void Maximize();
}

After that, I derive all my steps from RegistrationStep. If I need the step to be able to do one more thing, I simply add it to the interface, add abstract method to abstract class and implement it in the abstract class implementation... Or maybe not? Like, maybe sometimes I should add methods only to the abstract class and not to the interface?

My question is, how do I decide where to add new methods? Are there examples when its more reasonable to add methods to abstract class and not to the interface?

gnat
  • 21,442
  • 29
  • 112
  • 288
nicks
  • 533
  • 2
  • 6
  • 14
  • 1
    Related, but not a dupe: http://programmers.stackexchange.com/questions/41740/when-to-use-abstract-classes-instead-of-interfaces-with-extension-methods-in-c – Doc Brown Sep 15 '16 at 07:59
  • @gnat: that other title looks like a dupe of this one at a first glance, but the actual question is quite different. In that other question, the abstract class is not necessarily derived from the interface in stake. I was also thinking there must a dupe somewhere here on Programmer's, but I could not quickly find a real one, only red herrings. – Doc Brown Sep 15 '16 at 08:11
  • @DocBrown, You are right. I automatically read it as `IContentView`. :) My comment was pointless therefore. – David Arno Sep 15 '16 at 08:21
  • Is there any need for the `RegistrationStep` class? Since none of its methods are implemented, it provides nothing that `IRegistrationStep` doesn't, aside from inheriting from `ContentView`. – Dan Lyons Sep 15 '16 at 17:38
  • @DanLyons is there any need for the `IRegistrationStep` interface if it is only ever (directly) implemented by `RegistrationStep`? – Caleth Feb 08 '19 at 16:34
  • @Caleth If we're weighing inheriting from an abstract class versus implementing an interface, then I'll point out that class inheritance is like a marriage: it's great when things work out, but (in C#, at least) you can have only one partner, and it's extremely costly to dissolve the relationship, so you better be sure it's the right match for you. – Dan Lyons Feb 08 '19 at 19:19

3 Answers3

4

Apply the YAGNI principle: if it is sufficient to add the new method to the abstract class, add it only there - do not add anything to IRegistrationStep "you are not going to need (yet)". But if you have code which has a dependency on IRegistrationStep and which is going to use the new method, then you obviously need to add it in both places.

Doc Brown
  • 199,015
  • 33
  • 367
  • 565
3

In general, extending an interface is not a good idea. An interface should offer a single distinct functionality. If you need more later you should define an additional interface and implement that as well in your class.

Do you have a good reason to use interfaces? Do you expect to want and implement that interface on other classes that do not inherit from the same base class RegistrationStep inherits from? If not, there is probably no added value and you would be better off not using interfaces at all.

The name of your interface is not so nice. An interface defines behavior, not an object. That is why you will see names like IEnumerable and IDisposable rather than IEnumerator or IDisposer. Likewise, yours should be named IRegistrationSteppable. If that feels weird, that may just be another indicator interfaces are not appropriate for your problem.

Martin Maat
  • 18,218
  • 3
  • 30
  • 57
  • 1
    Indeed, I tend to find whenever I see "IClassName" (or "InterfaceNameImpl" it's a pretty sure sign the person is using an interface just because they think they are supposed to rather than for a concrete reason – Richard Tingle Sep 15 '16 at 14:40
  • An interface prescribes a minimal set of requirements of an object, which may include state besides behavior. IEnumerable and IDisposable define 'secondary' behaviors, while IEnumerator defines the main purpose of the implementing object. Here I find IRegistrationStep more appropriate (although I agree with you no interface is needed at all). – Philippe Sep 18 '16 at 17:45
0

The hard requirement for interfaces comes when you have to inherit from more than one thing.

(C# won't let you inherit from more than one class as this can cause some interesting ambiguity about what method to call in some edge cases)

So, say you have a ConcreteRegistrationStep which you want to inherit from the abstract but also implement some other functionality, say IDisposable. The fact that there is an IDisposable interface rather than an abstract class allows you to do inherit the interface and then be able to cast ConcreteRegistrationStep to a disposable.

Taking this logic further you can see that having an IRegistrationStep and using this in code which consumes RegistrationSteps rather than the abstract class will allow you or others more flexibility in future.

Ewan
  • 70,664
  • 5
  • 76
  • 161