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?
3 Answers 3
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.
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.
-
1Indeed, 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 reasonRichard Tingle– Richard Tingle2016年09月15日 14:40:27 +00:00Commented Sep 15, 2016 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– Philippe2016年09月18日 17:45:23 +00:00Commented Sep 18, 2016 at 17:45
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.
Explore related questions
See similar questions with these tags.
IContentView. :) My comment was pointless therefore.RegistrationStepclass? Since none of its methods are implemented, it provides nothing thatIRegistrationStepdoesn't, aside from inheriting fromContentView.IRegistrationStepinterface if it is only ever (directly) implemented byRegistrationStep?