0

My intuition tells me that moving duplicate/common codes among subclasses to the superclass (so superclass now have a new method) is a bad idea, but I have seen this technique used/described in both Design Pattern and Refactoring(e.g. pull up method) books. After some thinking my idea is that now subclasses' behavior is coupled to the superclass, and this will make someone who need to maintain the code to read the entire inheritance structure/tree to understand the logic in a subclass, if the hierarchy is large then it's hard to maintain it. Any advice?

  • So, let me ask you this. If we follow your argument to its logical conclusion, we would not have any code in the super class, so what’s the point of base classes at all? – RubberDuck Apr 16 at 9:49
  • @RubberDuck: That's the conclusion I want: In ideal world, we don't need inheritance. – Niing Apr 16 at 10:30
  • we don’t need inheritance, it can be completely replaced by composition. The only question then, is how do things compose nicely? Does a device have protocols? Or do protocols rely on a device? – RubberDuck Apr 16 at 10:37
  • @RubberDuck: I don't understand your questions. The responsibility of upper layers in a hierarchy is to define the big picture of what to do, not how to do it, so I still don't satisfied with current answers, in my opinion moving implementation to upper-layer is just a bad idea. (Reusability is a consequence of good design, not the reverse.) – Niing Apr 17 at 2:50
  • To understand what I mean one can refer to template method proposed in the book of GoF, the authors use only 4 pages (the shortest one among all patterns, which are all among 10~13 pages) to explain it, and it's heavily used in Android. – Niing Apr 17 at 2:55
1

You'll find a lot of resistance to large and/or deep class hierarchies, so I'm not suggesting that.  However,

Let's say you have three subclasses (S1,S2,S2), but only two of which (S1,S2) have common/duplicated behavior.  Because of the third class (S3), which doesn't share the common behavior, it is, in this case, not appropriate to pull methods up directly into the base class.  An alternative, then, is to introduce an intermediate subclass (B12) of the base, that the others (S1,S2) use for their base (leaving S3 alone).  Then pull up common subclass behaviors into that intermediate subclass.  This will avoid polluting the original base class with respect to the other subclasses (like S1).

Note that in languages with differentiation between interfaces and base/sub-classes, this can also be accomplished with interfaces — here one interface extends another — some concrete classes then implement the various interfaces as needed.  This offers the looser coupled of interfaces, while allowing that some are more specialized that the most general.

7

my idea is that now subclasses' behavior is coupled to the superclass

A subclasses behavior is always coupled to the superclass

this will make someone who need to maintain the code to read the entire inheritance structure/tree to understand the logic in a subclass

They will have always have to do that anyway.

if the hierarchy is large then it's hard to maintain it

That's why you shouldn't have large inheritance hierarchies, and prefer composition over inheritance in general.

  • Although I upvoted I don't agree with the first reply. By Liskov Substitution Principle, isn't subclassing adds another pre-condition: Subclasses depend on the superclass' behavior, while the superclass doesn't depend on anything? And I always consider inheritance for code reuse is a bad idea, because no one will reuse your code if it's hard to understand. – Niing Apr 16 at 10:37
  • 2
    The subclass directly using the superclasses behaviour by definition can't break LSP. A client of the type can't tell whether they have an object of the subclass or an object of the superclass, by it's behaviour, because it's the same method being called in both cases. – Caleth Apr 16 at 13:26
  • May I add: duplicate literal does not necessarily mean duplicate semantics. The duplicating code may serve another greater purpose and thus may change for different reasons. If that is the case we are talking a out two different methods according to LSP. And it is exactly those methods that are used for multiple different things that become those monsters we want to avoid – marstato Apr 16 at 16:52
  • @marstato: So you're talking about the case where two subclasses each have a method that does exaclty the same thing, but for different reasons, which may therefore change differently in the future? A bit of an exotic case, but certainly possible. Even them I'm not sure if it's better to forego the refactoring; you can always reverse it if necessary, and a method that should be split up is easier to recognize than one that is duplicated in another class. – Michael Borgwardt Apr 17 at 7:29
  • @MichaelBorgwardt yes, that case. depends on who is working on the project and how closely code is reviewed. if there is attention on such things i would agree to do the refactoring and reverse it when necessary. – marstato Apr 17 at 15:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.