views:

451

answers:

6

Hi all,

first question here, so hopefully you'll all go gently on me!

I've been reading an awful lot over the past few days about polymorphism, and trying to apply it to what I do in c#, and it seems there are a few different ways to implement it. I hope I've gotten a handle on this, but I'd be delighted even if I haven't for clarification.

From what I can see, I've got 3 options:

  1. I can just inherit from a base class and use the keyword 'virtual' on any methods that I want my derived classes to override.
  2. I could implement an abstract class with virtual methods and do it that way,
  3. I could use an interface?

From what I can see, if I don't require any implementation logic in the base, then an interface gives me the most flexibility (as I'm then not limiting myself with regards multiple inheritance etc.), but if I require the base to be able to do something on top of whatever the derived classes are doing, then going with either 1 or 2 would be the better solution?

Thanks for any input on this guys - I have read so much this weekend, both on this site and elsewhere, and I think I understand the approaches now, yet I just want to clarify in a language specific way if I'm on the right track. Hopefully also I've tagged this correctly.

Cheers, Terry

+2  A: 

All three of the above are valid, and useful in their own right. There is no technique which is "best". Only programming practice and experience will help you to choose the right technique at the right time.

So, pick a method that seems appropriate now, and implement away. Watch what works, what fails, learn your lessons, and try again.

abelenky
+6  A: 

An interface offers the most abstraction; you aren't tied to any specific implementation (useful if the implementation must, for other reasons, have a different base class).

For true polymorphism, virtual is a must; polymorphism is most commonly associated with type subclassing...

You can of course mix the two:

public interface IFoo {
    void Bar();
}
class Foo : IFoo {
    public virtual void Bar() {...}
}
class Foo2 : Foo {
    public override ...
}

abstract is a separate matter; the choice of abstract is really: can it be sensibly defined by the base-class? If there is there no default implementation, it must be abstract.

A common base-class can be useful when there is a lot of implementation details that are common, and it would be pointless to duplicate purely by interface; but interestingly - if the implementation will never vary per implementation, extension methods provide a useful way of exposing this on an interface (so that each implementation doesn't have to do it):

public interface IFoo {
    void Bar();
}
public static class FooExtensions {
    // just a silly example...
    public static bool TryBar(this IFoo foo) {
        try {
             foo.Bar();
             return true;
        } catch {
             return false;
        }
    }
}
Marc Gravell
I love using extenson methods in this way to create overloads. That way my interface is easy to implement, and the overloads are handled in the same way for all implementations.
Jacob Stanley
I really like this as an explaination Marc, both you and Yann below have put a lot of effort into explaining the answer, thankyou - obviously will wait to see what else comes in, but thanks - it really helps!
Terry_Brown
@Jacob - indeed; it is great for optional parameters (until we get C# 4.0) - for example, I tend to have "paged" versions of query methods on the interface, and use the extension method to provide the default "get everything" (simpler) overload - then I only have 1 method to implement at the concrete site, not 2/3/4/etc
Marc Gravell
marked this one as the answer for me at least - I'd still be keen to see others views on this thread, but the above really helped me, thanks Marc :)
Terry_Brown
+1  A: 

Interfaces are usually favored, for several reasons :

  • Polymorphisme is about contracts, inheritance is about reuse
  • Inheritance chains are difficult to get right (especially with single inheritance, see for instance the design bugs in the Windows Forms controls where features like scrollability, rich text, etc. are hardcoded in the inheritance chain
  • Inheritance causes maintenance problems

That said, if you want to leverage common functionnality, you can use interfaces for polymorphism (have your methods accept interfaces) but use abstract base classes to share some behavior.

public interface IFoo
{
    void Bar();
    enter code here
}

will be your interface

public abstract class BaseFoo : IFoo
{
    void Bar
  {
        // Default implementation
  }
}

will be your default implementation

public class SomeFoo : BaseFoo
{

}

is a class where you reuse your implementation.

Still, you'll be using interfaces to have polymorphism:

public class Bar
{
   int DoSometingWithFoo(IFoo foo)
{

    foo.Bar();
}
}

notice that we're using the interface in the method.

Yann Schwartz
really like your summary at the top of this post too Yann - I think it helps just focus the mind at a high level.
Terry_Brown
+1  A: 

The first thing you should ask is "why do I need to use polymorphism?", because polymorphism is not and end by itself, but a mean to reach an end. Once you have your problem well defined, it should be more clear which approach to use.

Anyway, those three aproaches you commented are not exclusive, you still can mix them if you need to reuse logic between just some classes but not others, or need some distinct interfaces...

fortran
absolutely - I guess the above wasn't so much about looking to use polymorphism for the sake of it, more to understand the approaches, and when I'd use each (or as you say, mix and match to suit)
Terry_Brown
+1  A: 
  • use abstract classes to enforce a class structure
  • use interfaces for describing behaviors
AB Kolan
A: 

It really depends on how you want to structure your code and what you want to do with it.

Having a base class of type Interface is good from the point of view of testing as you can use mock objects to replace it.

Abstract classes are really if you wish to implement code in some functions and not others, as if an abstract class has nothing other than abstract functions it is effectively an Interface.

Remember that an abstract class cannot be instantiated and so for working code you must have a class derived from it.

In practice all are valid.

I tend to use an abstract class if I have a lot of classes which derive from it but on a shallow level (say only 1 class down).

If I am expecting a deep level of inheritence then I use a class with virtual functions.

Eitherway it's best to keep classes simple, along with their inheritence as the more complex they become the more likelyhood of introducing bugs.

ChrisBD
aside: "and so for working code you must have a class derived from it" - actually, there are ways of *usefully* using both interfaces and abstract classes without **ever** having a concrete implementation... very much an edge case, but doable - by using Expression to indicate *intent* (useful in RPC etc), without actually ever having to *call* any of the methods.
Marc Gravell