Interface vs Base class

后端 未结 30 2554
甜味超标
甜味超标 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条回答
  • 2020-11-21 08:00

    When I first started learning about object-oriented programming, I made the easy and probably common mistake of using inheritance to share common behavior - even where that behavior was not essential to the nature of the object.

    To further build on an example much used in this particular question, there are lots of things that are petable - girlfriends, cars, fuzzy blankets... - so I might have had a Petable class that provided this common behavior, and various classes inheriting from it.

    However, being petable is not part of the nature of any of these objects. There are vastly more important concepts that are essential to their nature - the girlfriend is a person, the car is a land vehicle, the cat is a mammal...

    Behaviors should be assigned first to interfaces (including the default interface of the class), and promoted to a base class only if they are (a) common to a large group of classes that are subsets of a larger class - in the same sense that "cat" and "person" are subsets of "mammal".

    The catch is, after you understand object-oriented design sufficiently better than I did at first, you'll normally do this automatically without even thinking about it. So the bare truth of the statement "code to an interface, not an abstract class" becomes so obvious you have a hard time believing anyone would bother to say it - and start trying to read other meanings into it.

    Another thing I'd add is that if a class is purely abstract - with no non-abstract, non-inherited members or methods exposed to child, parent, or client - then why is it a class? It could be replaced, in some cases by an interface and in other cases by Null.

    0 讨论(0)
  • 2020-11-21 08:00

    An inheritor of a base class should have an "is a" relationship. Interface represents An "implements a" relationship. So only use a base class when your inheritors will maintain the is a relationship.

    0 讨论(0)
  • 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<Dog>();
        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<ISwimable>();
    
          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!

    0 讨论(0)
  • 2020-11-21 08:02

    It depends on your requirements. If IPet is simple enough, I would prefer to implement that. Otherwise, if PetBase implements a ton of functionality you don't want to duplicate, then have at it.

    The downside to implementing a base class is the requirement to override (or new) existing methods. This makes them virtual methods which means you have to be careful about how you use the object instance.

    Lastly, the single inheritance of .NET kills me. A naive example: Say you're making a user control, so you inherit UserControl. But, now you're locked out of also inheriting PetBase. This forces you to reorganize, such as to make a PetBase class member, instead.

    0 讨论(0)
  • 2020-11-21 08:02

    Regarding C#, in some senses interfaces and abstract classes can be interchangeable. However, the differences are: i) interfaces cannot implement code; ii) because of this, interfaces cannot call further up the stack to subclass; and iii) only can abstract class may be inherited on a class, whereas multiple interfaces may be implemented on a class.

    0 讨论(0)
  • 2020-11-21 08:03

    Another option to keep in mind is using the "has-a" relationship, aka "is implemented in terms of" or "composition." Sometimes this is a cleaner, more flexible way to structure things than using "is-a" inheritance.

    It may not make as much sense logically to say that Dog and Cat both "have" a Pet, but it avoids common multiple inheritance pitfalls:

    public class Pet
    {
        void Bathe();
        void Train(Trick t);
    }
    
    public class Dog
    {
        private Pet pet;
    
        public void Bathe() { pet.Bathe(); }
        public void Train(Trick t) { pet.Train(t); }
    }
    
    public class Cat
    {
        private Pet pet;
    
        public void Bathe() { pet.Bathe(); }
        public void Train(Trick t) { pet.Train(t); }
    }
    

    Yes, this example shows that there is a lot of code duplication and lack of elegance involved in doing things this way. But one should also appreciate that this helps to keep Dog and Cat decoupled from the Pet class (in that Dog and Cat do not have access to the private members of Pet), and it leaves room for Dog and Cat to inherit from something else--possibly the Mammal class.

    Composition is preferable when no private access is required and you don't need to refer to Dog and Cat using generic Pet references/pointers. Interfaces give you that generic reference capability and can help cut down on the verbosity of your code, but they can also obfuscate things when they are poorly organized. Inheritance is useful when you need private member access, and in using it you are committing yourself to highly coupling your Dog and Cat classes to your Pet class, which is a steep cost to pay.

    Between inheritance, composition, and interfaces there is no one way that is always right, and it helps to consider how all three options can be used in harmony. Of the three, inheritance is typically the option that should be used the least often.

    0 讨论(0)
提交回复
热议问题