开发者

Breaking polymorphism vs. subclasses with unused inherited members

开发者 https://www.devze.com 2022-12-09 18:37 出处:网络
If I use inheritance, and later realize that a single subclass needs a method or fie开发者_Go百科ld that is not available, should I declare that in the base class and not have it implemented in the ot

If I use inheritance, and later realize that a single subclass needs a method or fie开发者_Go百科ld that is not available, should I declare that in the base class and not have it implemented in the other subclasses, or should I declare it in that single subclass?

If I choose to declare the method in the subclass, then I can no longer treat everything polymorphically. On the other hand, if I choose to put it in the base class then I end up with a lot of subclasses not implementing the property or method. I have seen examples in the .net framework where the 'not implemented' approach is chosen. What is the best way to go?


If only one subclass has method X, of course you can't call X polymorphically, by definition. Is it reasonable for X to exist in the superclass (and therefore everywhere) but be a no-op in most cases? Sometimes it is, sometimes you just have to rethink your whole class hierarchy, i.e., why do you want to call X polymorphically, even where it might not exist (or at best be a no-op)? It's impossible to respond without knowing much, much more about your specific use case!


A method does not belong in a base class unless every possible derived class has an appropriate implementation.

If you have to throw NotSupportedException in some of your derivations, then you have broken the Liskov Substitution Principle. This principal basically states than any derived class should be appropriate whenever a base class is expected.

The public interface to a class should be as cohesive as possible. If I'm confronted with such a choice, I'll almost always put it into the derived class unless I really think the operation 'belongs' in the base.

Update

I would like to retract my previous statement. As Wayne Hartman has pointed out, if that were true, then System.IO.Stream would break the LSP also. The rule states that you cannot throw new exceptions from a method in the subtype. This doesn't seem to apply to abstract methods, since they don't have any implementation.

I think the important point is to keep your abstraction pure. If it makes sense in the terms of your abstraction to add the method into the base class, then by all means do it. If, however, you just want to have a common place to add code, then I would avoid adding it to the base.

I also agree that sometimes partial implementation for consistency is appropriate.


is it a specialized method at only one subbclass needs? then implement in the sub class. Otherwise implement as a virtual in the base class that throws a NotImplementedException. Then in any class that needs it add as override.


If it will only be used in the subclass and doesn't need to be called polymorphically, then implement it only in the subclass. However, if you need to use it polymorphically then think about what that function would mean for other subclasses of the super class.

If there is no good meaning for that function, then you may need to rethink your class hierarchy. However, you can just do No-op or throw a NotImplementedException for subclasses where the function has no valid meaning. I'm not really a fan of either, but sometimes there isn't a way around using those.


I've always preferred to use NotImplemented style exceptions for code that isn't finished yet. I would never personally use it just so I could push more methods into a base class.


For this one you need to answer some questions about the intent of your API.

  1. How is your API to be used: If your API consumers are to almost always refer to your base class, then it may make sense to put it into the base class.
  2. If the method your trying to implement is applicable to almost all derived classes that could choose to implement the functionality, then put it in the base class.

Consider System.IO.Stream, this is an abstract class with abstract methods for seek operations, it makes sense to not have to derive from something like System.IO.SeekableStrem just to get seek functionality, users of the API should only refer to Stream.

0

精彩评论

暂无评论...
验证码 换一张
取 消