0

Sorry guys, I should have clarified the fact that the modified method is abstract in Father. Then if the method signature changes, all its implementations in SonX shall also change(at least the signature, though the implementation may stay still).

Now the question should be asked like following: Say I have the abstract class Father, and three(or more) of his children class Son1, Son2 and Son3. Now I have to change one method, in other words, add an argument to one abstract method of Father. However, I will have to change all the implemented methods(the modified abstract method in Father) in SonX, which costs too much. The change to the signature of the method in SonX is essential cause the clients are interacting with SonX and the clients shall invoke the new version of the method.

So my question is: is there any design pattern suitable for such a situation in which the interfaces will change?

Thanks.

migrated from stackoverflow.com Dec 20 '14 at 12:45

This question came from our site for professional and enthusiast programmers.

  • 3
    Yeah. Separate the functionality and the classes using a Visitor Pattern. – christopher Dec 19 '14 at 1:42
  • 1
    Christopher has a point... but I'd challenge the question entirely on two grounds. One: why is it expensive to update the signature of an inherited method in subclasses? It's relatively low cost if you use refactoring tools. Two: what would it mean to implementors of the method if the method changes and they stay the same? I think perhaps your start point is wrong. One suggestion, though, implement the interface with a base class that the subclasses further extend - this might protect them more against "boilerplate change". – Ashley Frieze Dec 19 '14 at 1:55
  • Frieze, thanks for replying. In fact, I have to change not only the signature of the methods but also their implementations. I have more than 6 such methods need change and the clients interacting with them also have to change as a consequence. That is not a trivial work to modify the code. – qingjinlyc Dec 19 '14 at 2:08
  • 2
    Can you elaborate on the kind of change, please? Why do you need to add the parameter and change the implementation? If you have decided to change the semantics of that method, you cannot really expect the change to not require any re-writing effort. And in what way are the implementations of the method different in the derived classes? Do they share anything? – 5gon12eder Dec 19 '14 at 2:31
  • 1
    @qingjinlyc Can't you just overload method with one more parameter in the base abstract class like this link dotnetfiddle.net/0twPAU – Jenish Rabadiya Dec 19 '14 at 6:10
4

The fact that you need to make a change to the interface of a superclass but do not also have a similar need to change its subclasses suggests to me that you have a design error of some kind. Your subclasses would appear, at least in some cases, not to be substitutable for their base class, otherwise they would need to change too.

It may be that your inheritance structure is wrong in that there is an as yet unidentified base class that all of Father and SonX should inherit instead of being direct descendants. Then Father alone could implement the method that needs to change. If there is behavior in common it might belong in the base class, or it may be better if SonX have a Father object they can delegate to.

  • I agree with this. If I understand your understanding :), in this case Father and SonX do not share directly an IS A relationship required for inheritance. They are "possibly" decedents of another more abstract parent. If they are or not, the point is, they are not directly an IS A relationship and therefore SonX should not be inherited from Father directly. – FranAsm Dec 20 '14 at 22:23
2

I feel many people implement inheritance too quickly. Using it as a tool to reduce code. This is not the purpose for inheritance. Used like this, you will always have these problems because inheritance is not implemented properly.

On the basics, inheritances spells out a relationship between 2 classes. The relationship is called an "IS A" relationship. In your case, SonX as you describe, is not conforming to this relationship. It is not a Father. Let me explain...

The basic SOLID principles of which in particular I draw your attention to the L part (LSP for Liskov substitution principle). States that any child class should be able to directly replace its parent. If it cannot do this, then it does not conform to proper inheritance.

You find yourself breaking this rule whenever you directly override parent methods in child classes. Parent methods should be overloaded using polymorphism by adding another method of the same name with different parameters, not directly overridden. For example...

Father class has a method Foo. Therefore, by inheriting this class to Son, you are saying that Son IS A Father. Therefore Son should also have method Foo.

If you declare method Foo as virtual in father, so it can be directly overridden in Son, and then override it, then Son no longer conforms to the IS A relationship. As the Foo method in Son does something different than it was originally defined in father.

However, if you overload Foo in the Son class and give it a different signature to allow it to do its job. Then technically, Son can still do all the things Father can do along with a few extras of its own in the overloaded Foo. This is because the original Foo inherited from the Father, is still intact and fully working.

If you really must have a design pattern to decouple abstractions (which is also a good practice in general), there is a design pattern called the bridge pattern and the Visitor Pattern among others (as recommended in the comments by Christopher and Jordao). But I do highly encourage a full working (meaning you have done a few examples of each in actual code so its not a theoretical) understanding of all the SOLID principles first.

I'd also recommend a simpler pattern too. Introduce Parameter Object. It generally applies if you have methods with a lot of parameters (personally I feel more than 3 or 4), where you make a class and pass that around instead.

Don't forget also that you can inherit and extend interfaces and abstract classes and then inherit from those child classes or interfaces. But the bridge pattern is probably better choice due to the decoupling it offers.

Hope this helps.

  • 1
    I strongly disagree with your interpretation of the LSP - overloading a method absolutely can be the correct thing to do and can be the best way of complying with the LSP in many cases. Just because an object has a different implementation of a method doesn't mean it does something different at a conceptual level. – Jules Dec 20 '14 at 20:12
  • @Jules So if I understand correctly...its the same but different, or different but the same, not sure which? :) – FranAsm Dec 20 '14 at 22:29
  • For example, in the classic (and imperfect) example of Animals, the subclasses all override the speak() method. A Dog says "bark" and a Cat says "meow". – user949300 Dec 21 '14 at 7:00
  • Assuming that animal is not a virtual method and actually has some functionality of its own then this is the classic example of inheritance being wrongly used to save code. So if any class that uses animal, now switches to using dog or cat, the functionality is broken. Therefore doesn't conform to LSP and shouldn't be using inheritance. While conceptually they are indeed animals, functionally they are not because their behaviours are different if overridden without being overloaded. – FranAsm Dec 21 '14 at 23:55
  • 1
    @FranAsm The link is here : objectmentor.com/resources/publishedArticles.html unfortunately, you have to click on "design principles" to get to the list (the site is a little weird). Happy holidays! :-) – Lovis Dec 25 '14 at 18:18

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.