开发者

Is an interface and an abstract class with just virtual abstract methods the same thing?

If I have a project that contains similar classes and some may use the same implementation, but in most cases they implement their own way of handling the methods defined in an interface or abstract class. I am trying to figure out if an interface/abstract class is better or not. I don't get the point of an interface if you ca开发者_如何学编程n just use an abstract class with virtual abstract methods.

Here is an interface:

public interface IAthlete
{
    void Run();
}

Here is an abstract class:

public abstract class Athlete
{
    public abstract void Run();
}

Here is an implementation of the interface:

public class Sprinter : IAthlete
{
    public void Run()
    {
        Console.WriteLine("Running Fast....");
    }
}

Here is an extension of the abstract class:

public class MarathonRunner : Athlete
{
    public override void Run()
    {
         Console.Write("Jogging....");
    }
 }

Now if I decide to add a method called Stop to either the interface or abstract method, Sprinter and MarathonRunner both break and because I can provide some default implementation to abstract, it seems like a better choice. Am I missing something?


There are 2 main differences between Interfaces and abstract super-classes:

Abstract Classes

  • code reuse is possible by using an abstract super-class
  • you can only inherit one super-class

Interfaces

  • every method has to be implemented in each sub-class
  • a class can inherit more than 1 interface (multiple inheritance)


In the case where all you have is one piece of commonality to extract, you're quite right that there isn't a substantive difference between the two. But this is rather like saying "in the case of adding 1 to 2, there's no difference between an int and a double" - it's technically true, but not a particularly useful guide to how to think.

In case with any more complexity than this (that is, in most cases) there will be more classes, and pieces of common baheaviour to extract. Then you have to start making a significant choice between class inheritance and interface implementation, taking into account things like:

  • you only get one shot at choosing a base class, but you can implement as many interfaces as you like
  • if you want your 'parent' to do any work, it needs to be a class not an interface

and so on.

In general, the semantics of your classes should guide you - where the 'things' have an "IS A" relationship (like MarathonRunner to Athlete), inheritance is suggested; where the 'things' have an "I CAN FULFIL THE CONTRACT OF A" (like, say, Person to Runner), interface implementation is suggested.


Interfaces are a btter way to go as the current consensus amongst the .NET developer comunity is that you should favour composition over inheritance, so Interfaces are a much better strategy (think of Injection Containers and how usefull they are as well, and lets not get started on unit testing). also, classes can implement many interfaces but can only inherit from one class (abstract or otherwise). also structs can implement interfaces but not inherit from another class. At the runtime level, interfaces are more efficient as the runtime doesnt have to walk the inheritance stack in order to work out the polymorphic implications of calling a specific member.


Interfaces are a very useful feature, and are very similar to abstract classes, and in some circumstances, exchangable with abstract classes.

But, don't jump straight to interfaces, unleass you have to (very common antipattern in Java developers). I suggest, by reading your example, to stick to abstract classes.

Most of the times I only use interfaces, when I have several non related classes, and I need them to have common members, as If these classes came from the same base class.

In your example, you are trying to find what happen if you need a new stop method, when adding a base virtual method. These can be solved in a different approach, that is not Abstract Classes versus interfaces.

There are 3 choices:

(1) Add an abstract method that coerce the programmer to override it, in order to instantiate objects.

(2) Add a new virtual method that does something, but doesn't have to be overriden.

(3) Add a new method that does nothing, maybe applies to your case.

// cannot instantiate an abstract class
public abstract class Athlete
{
    // helper method:
    public /* non-abstract */ void DoNothing()
    {
      // does nothing on purpouse !!!
    }

    // (1) virtual & abstract method, must be overriden
    public abstract void Run();


    // (2) new virtual method, doesn't need to be overriden,
    // but, maybe you dont like what it does
    public virtual void Stop()
    {
       Message.Show("Stop !!!");
    }

    // (3) new virtual method, doesn't need to be overriden,
    // its safe to be called
    public virtual void TakeBreak()
    {
      // works like an abstract virtual method, but, you don't need to override
      DoNothing();
    }
} // class Athlete

// in a non abstract class, you must override all abstract methods
public /* non-abstract */ class Runner: Athlete
{
    public override void Run()
    {
       DoNothing(); 
    }

    public override void Stop()
    {
       DoNothing(); 
    }

    // don't need to override this method
    // public virtual void TakeBreak();

} // class Trekker

// ...

Runner ARunner = new Runner();
ARunner.Run();
ARunner.Stop();
ARunner.TakeBreak();

The third kind of virtual method, that may apply to your example, doesnt' have a special name, I already post a question about it on stackoverflow, but, nobody knew an special name for this case.

Cheers.


An important difference between interfaces and abstract classes is how their members handle multi-generational inheritance. Suppose there's an abstract class BaseFoo with abstract method Bar and interface IFoo with method Boz; class Foo inherits BaseFoo and implements IFoo, and class DerivedFoo inherits from Foo.

If DerivedFoo needs to override BaseFoo.Bar, it may do so, and its override may call base.Bar() if it needs to use its parent's implementation. If Foo implements Boz implicitly using a virtual method, then DerivedFoo may override that method and call base.Boz() (the override being a function of the class rather than the interface) but if Foo explicitly implements IFoo.Boz, then the only way for DerivedFoo to change the behavior of IFoo.Boz will be to re-implement it. If it does so, then Foo's implementation of IFoo.Boz will become inaccessible, even within DerivedFoo's implementation of the same interface member.

0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜