Interfaces/multiple inheritance/restricted inheritance in .NET

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • Liz Macfie
    New Member
    • Jul 2010
    • 1

    #1

    Interfaces/multiple inheritance/restricted inheritance in .NET

    Hi,

    We're in the process of setting up a class hierarchy, but are encountering some issues. We wondered whether any of you with more experience might be able to lend a hand, please?

    At present, we have an abstract base class called Entity. Inheriting from this are ClassA, ClassB and ClassC. The vast majority of properties/methods in Entity are usable in all child classes. However, we come across some instances as below:

    Entity has the method Move(). ClassA and ClassC can be moved, but ClassB cannot.

    Do you have any advice for an appropriate way to implement this, please? We have looked at:

    1) Having all the code in Entity, and then in ClassB.Move() throwing a NotImplemented exception. This is not ideal because the code compiles, but only dies at runtime.

    2) Having an IMovable interface that contains the Move() function, and is implemented by ClassA and ClassC:
    a) with the Move code defined in both classes - not ideal because of code duplication
    b) with the Move code defined in a static Helper class and called within each class - not ideal if the method signature ever has to be changed
    c) with the Move code defined as a protected method in Entity, with ClassA and ClassC calling base.Move() - not ideal for the same reason as above

    Thanks in advance for any advice,

    Liz
  • Jeremy Walker
    New Member
    • Jul 2010
    • 3

    #2
    I think a mixture of 1 and 2.

    ClassA should either:
    * Implement IMoveable (because presumably you are going to use IMoveables in method signatures?)
    * Throw a NotImplementedE xception and use an #error preprocessor directive to stop it from compiling.

    In VB, you can't implicitly implement the interface, so this won't work, but it should work in C#. If you need to use VB, then implement IMoveable in Entity. However, this stops being compile-safe.

    Jez

    Comment

    • GaryTexmo
      Recognized Expert Top Contributor
      • Jul 2009
      • 1501

      #3
      Even having IMovable means you'll have to duplicate the implementation in ClassA and ClassC. Perhaps ClassB should actually be the base class, or another step along the way? What about...

      Code:
      public class Entity { ... }
      public interface IMovable { // defines Move() }
      public class MovableEntity : Entity,IMovable { // implements Move() }
      
      public class ClassA : MovableEntity { ... }
      public class ClassB : Entity { ... }
      public class ClassC : MovableEntity { ... }
      Something like that?
      Last edited by GaryTexmo; Jul 20 '10, 04:49 PM. Reason: Removing perhaps abuse! ><

      Comment

      • Jeremy Walker
        New Member
        • Jul 2010
        • 3

        #4
        You can write the implementation code in Entity and then implicitly implement IMoveable in the child classes without any duplication.

        Changing the hierarchy would work if IMoveable is a one off, but if it is one of a number of possible options (e.g. IRoatable, ISpinable etc), then you'd this wouldn't work.

        Another option would be to have Move/Rotate etc as static functions (on Entity or on a static helper class). The functions would take an IMoveable. The correct classes then implement IMoveable, which is an interface with the properties needed to run the code (again just defined once in Entity). This is probably the cleanest way of doing it.

        Comment

        • GaryTexmo
          Recognized Expert Top Contributor
          • Jul 2009
          • 1501

          #5
          You can write the implementation code in Entity and then implicitly implement IMoveable in the child classes without any duplication.
          How do you do this without a class higher up the hierarchy getting that method? I don't think you can hide methods from the inheritance tree... maybe I don't know what you mean.

          Changing the hierarchy would work if IMoveable is a one off, but if it is one of a number of possible options (e.g. IRoatable, ISpinable etc), then you'd this wouldn't work.
          You can use multiple inheritance with interfaces

          Code:
          public MovableEntity : Entity,IMovable,IRotatable,IScalable { ... }

          Comment

          • Jeremy Walker
            New Member
            • Jul 2010
            • 3

            #6
            Hi Gary,

            My initial suggestion was based around the fact that the "vast majority" of child classes would need the methods. Thus the idea of using the #error preprocessor directive to stop the few unwanted classes from having the method. It's not ideal, but I'd say it's about the same level of undesirability as having duplicated code in every child class. I am aware that it's still not complier safe.

            My issue with having the multiple inheritance routes you suggested was that if you had various features that needed distributing to different objects, you would once again end up with duplication. So you would need an implementation of Move(), but then two implementations of Rotate() depending on whether the class can move+rotate or just rotate.

            To modify your code slightly...

            Code:
            public class Entity { ... }
            
            public interface IMovable { // defines Move() }
            public class MovableEntity : Entity,IMovable { // implements Move() }
            
            public interface IRotatable { // defines Rotate() }
            public class RotatableEntity : Entity,IRotate { // implements Rotate() }
            
            public class MovableAndRotatableEntity : Moveable, IRotate { // implements Rotate() }
            
            public class ClassA : Entity { ... }
            public class ClassB : MovableEntity { ... }
            public class ClassC : RotatableEntity { ... }
            public class ClassD : MovableAndRotatableEntity { ... }
            I think static methods, with IMoveble/IRotatable interfaces exposing necessary methods/properties for use in the Move()/Rotate() functions is the best way forward.

            Comment

            • GaryTexmo
              Recognized Expert Top Contributor
              • Jul 2009
              • 1501

              #7
              Yea, you could do that I guess, but I wouldn't recommend it. Typically I would have organized them together (as I posted above) since if you want an object that moves, having support for rotation and scaling is also appropriate.

              That's generally how I organize my projects that work this way (ie, game stuff) and it works out fairly well for me. Of course, just 'cause that's how I do it doesn't mean it's how everybody else does it! ;)

              Static methods on Entity, which take another entity are definitely an option too. Personally I'm not a fan because the functionality for the object isn't contained within the object itself (ie, I like the object to move itself), but that doesn't make it wrong.

              Hopefully between the two of us, we've provided enough to help the original poster figure out their problem :)

              Comment

              • Joseph Martell
                Recognized Expert New Member
                • Jan 2010
                • 198

                #8
                I watched a video here about game development on the android platform. The speaker actually mentioned this exact predicament. The more methods that need to be included/excluded but do not necessarily depend on each other, the more complex the inheritance hierarchy gets.

                If some objects are movable and some are not, then it can be argued that "move()" is not a valid method to include in the base class because not all sub-objects will obey the same interface. Using inheritance as the go-to solution means that every new possible combination of methods requires a new inheritance chain.

                The proposed solution in the video was to rely on composition instead of inheritance. Basically, you define a movable component and if an object is movable, then you give it a movable component. If an object is displayable, then you give it a displayable object. It is a big shift in paradigm from inheritance. The objects aren't polymorphic like they are when using inheritance (although each component is) so the program structure must be handled differently.

                The plus side is that components can be added to and removed from an object at run-time to modify behavior. It also becomes simpler to do things like a subscriber pattern or factory patterns because each possible behavior is isolated.

                Its just a thought. This doesn't work in all cases, but if inheritance is proving to be very difficult and overly complex, it might be worth exploring the composition option.

                Comment

                Working...