Interface vs Base class

后端 未结 30 2529
甜味超标
甜味超标 2020-11-21 07:34

When should I use an interface and when should I use a base class?

Should it always be an interface if I don\'t want to actually define a base implementation of the

30条回答
  •  慢半拍i
    慢半拍i (楼主)
    2020-11-21 08:02

    Source: http://jasonroell.com/2014/12/09/interfaces-vs-abstract-classes-what-should-you-use/

    C# is a wonderful language that has matured and evolved over the last 14 years. This is great for us developers because a mature language provides us with a plethora of language features that are at our disposal.

    However, with much power becomes much responsibility. Some of these features can be misused, or sometimes it is hard to understand why you would choose to use one feature over another. Over the years, a feature that I have seen many developers struggle with is when to choose to use an interface or to choose to use an abstract class. Both have there advantages and disadvantages and the correct time and place to use each. But how to we decide???

    Both provide for reuse of common functionality between types. The most obvious difference right away is that interfaces provide no implementation for their functionality whereas abstract classes allow you to implement some “base” or “default” behavior and then have the ability to “override” this default behavior with the classes derived types if necessary.

    This is all well and good and provides for great reuse of code and adheres to the DRY (Don’t Repeat Yourself) principle of software development. Abstract classes are great to use when you have an “is a” relationship.

    For example: A golden retriever “is a” type of dog. So is a poodle. They both can bark, as all dogs can. However, you might want to state that the poodle park is significantly different than the “default” dog bark. Therefor, it could make sense for you to implement something as follows:

    public abstract class Dog
    {
          public virtual void Bark()
          {
            Console.WriteLine("Base Class implementation of Bark");
          }
    }
    
    public class GoldenRetriever : Dog
    {
       // the Bark method is inherited from the Dog class
    }
    
    public class Poodle : Dog
    {
      // here we are overriding the base functionality of Bark with our new implementation
      // specific to the Poodle class
      public override void Bark()
      {
         Console.WriteLine("Poodle's implementation of Bark");
      }
    }
    
    // Add a list of dogs to a collection and call the bark method.
    
    void Main()
    {
        var poodle = new Poodle();
        var goldenRetriever = new GoldenRetriever();
    
        var dogs = new List();
        dogs.Add(poodle);
        dogs.Add(goldenRetriever);
    
        foreach (var dog in dogs)
        {
           dog.Bark();
        }
    }
    
    // Output will be:
    // Poodle's implementation of Bark
    // Base Class implementation of Bark
    
    // 
    

    As you can see, this would be a great way to keep your code DRY and allow for the base class implementation be called when any of the types can just rely on the default Bark instead of a special case implementation. The classes like GoldenRetriever, Boxer, Lab could all could inherit the “default” (bass class) Bark at no charge just because they implement the Dog abstract class.

    But I’m sure you already knew that.

    You are here because you want to understand why you might want to choose an interface over an abstract class or vice versa. Well one reason you may want to choose an interface over an abstract class is when you don’t have or want to prevent a default implementation. This is usually because the types that are implementing the interface not related in an “is a” relationship. Actually, they don’t have to be related at all except for the fact that each type “is able” or has “the ablity” to do something or have something.

    Now what the heck does that mean? Well, for example: A human is not a duck…and a duck is not a human. Pretty obvious. However, both a duck and a human have “the ability” to swim (given that the human passed his swimming lessons in 1st grade :) ). Also, since a duck is not a human or vice versa, this is not an “is a” realationship, but instead an “is able” relationship and we can use an interface to illustrate that:

    // Create ISwimable interface
    public interface ISwimable
    {
          public void Swim();
    }
    
    // Have Human implement ISwimable Interface
    public class Human : ISwimable
    
         public void Swim()
         {
            //Human's implementation of Swim
            Console.WriteLine("I'm a human swimming!");
         }
    
    // Have Duck implement ISwimable interface
    public class Duck: ISwimable
    {
         public void Swim()
         {
              // Duck's implementation of Swim
              Console.WriteLine("Quack! Quack! I'm a Duck swimming!")
         }
    }
    
    //Now they can both be used in places where you just need an object that has the ability "to swim"
    
    public void ShowHowYouSwim(ISwimable somethingThatCanSwim)
    {
         somethingThatCanSwim.Swim();
    }
    
    public void Main()
    {
          var human = new Human();
          var duck = new Duck();
    
          var listOfThingsThatCanSwim = new List();
    
          listOfThingsThatCanSwim.Add(duck);
          listOfThingsThatCanSwim.Add(human);
    
          foreach (var something in listOfThingsThatCanSwim)
          {
               ShowHowYouSwim(something);
          }
    }
    
     // So at runtime the correct implementation of something.Swim() will be called
     // Output:
     // Quack! Quack! I'm a Duck swimming!
     // I'm a human swimming!
    

    Using interfaces like the code above will allow you to pass an object into a method that “is able” to do something. The code doesn’t care how it does it…All it knows is that it can call the Swim method on that object and that object will know which behavior take at run-time based on its type.

    Once again, this helps your code stay DRY so that you would not have to write multiple methods that are calling the object to preform the same core function (ShowHowHumanSwims(human), ShowHowDuckSwims(duck), etc.)

    Using an interface here allows the calling methods to not have to worry about what type is which or how the behavior is implemented. It just knows that given the interface, each object will have to have implemented the Swim method so it is safe to call it in its own code and allow the behavior of the Swim method be handled within its own class.

    Summary:

    So my main rule of thumb is use an abstract class when you want to implement a “default” functionality for a class hierarchy or/and the classes or types you are working with share a “is a” relationship (ex. poodle “is a” type of dog).

    On the other hand use an interface when you do not have an “is a” relationship but have types that share “the ability” to do something or have something (ex. Duck “is not” a human. However, duck and human share “the ability” to swim).

    Another difference to note between abstract classes and interfaces is that a class can implement one to many interfaces but a class can only inherit from ONE abstract class (or any class for that matter). Yes, you can nest classes and have an inheritance hierarchy (which many programs do and should have) but you cannot inherit two classes in one derived class definition (this rule applies to C#. In some other languages you are able to do this, usually only because of the lack of interfaces in these languages).

    Also remember when using interfaces to adhere to the Interface Segregation Principle (ISP). ISP states that no client should be forced to depend on methods it does not use. For this reason interfaces should be focused on specific tasks and are usually very small (ex. IDisposable, IComparable ).

    Another tip is if you are developing small, concise bits of functionality, use interfaces. If you are designing large functional units, use an abstract class.

    Hope this clears things up for some people!

    Also if you can think of any better examples or want to point something out, please do so in the comments below!

提交回复
热议问题