This question occurred to me when an answer was proposed to another question I asked. Suppose I have a base class
public abstract class BaseClass {}
with some decent number of derived classes- let's say more than half a dozen. Most of those derived classes share no similarity beyond what they inherit from the base class, but two of them have a similarity like so
public class OneOfMyDerivedClasses : BaseClass
{
public string SimilarProperty {get; set;}
//Other implementation details
}
public class AnotherOneOfMyDerivedClasses : BaseClass
{
public string SimilarProperty {get; set;}
//Other implementation details, dissimilar to those in OneOfMyDerivedClasses
}
That's it. That's the only similarity that any of the subclasses share beyond what was inherited from BaseClass
. In my actual application I've solved this with an interface IHaveSimilarProperty
defining the single SimilarProperty
property, as all I care about is that an object implements said interface in use. But since I have duplication, should I be defining an intermediate base class for these two derived classes to inherit from, ie
public abstract IntermediateBaseClass : BaseClass
{
public string SimilarProperty {get; set;}
}
I could also combine both approaches, decorating the intermediate class with the interface...
So my question is around whether or not this is sufficient duplication to warrant an intermediate base class in terms of OOP best practices. Should I aggressively eliminate all duplication at every turn or should I take a more pragmatic approach? If the latter, what are the rules of thumb that would push me to choose one approach over the other?
Any design pattern can be taken to extremes. Here's some general guidelines I would use when deciding whether or not to subclass:
In your case, since the only similarity seems to be a property with the same name in both classes, it probably isn't worth it to subclass.
You should decide on subclassing based on the common semantic of your classes, not merely on their common attributes. Sharing a common property is not enough to warrant an intermediate common subclass, but sharing a common semantics would definitely be enough.
Here is an example: a Rectangle
and a Circle
classes may have a property called Center
, but it does not mean that the two classes should have a common subclass (apart from the abstract Shape
, which may not necessarily have a Center
). In this situation, an interface IWithCenter
fits a lot better. Similarly, a Label
and an TextField
may have a property Text
, but in this case even a common interface would be unwarranted.
It's fine to aggressively eliminate duplication at every turn, but your #1 tool for doing so is composition, not inheritance. Use inheritance when you need polymorphism, use composition when you need reuse.
...but if the "duplication" in question is just one property, then maybe don't worry about it. The golden rule of refactoring is that each refactoring should make your life better instead of worse. If it doesn't, you're doing it wrong.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With