When to use an interface instead of an abstract class and vice versa?

前端 未结 23 2141
忘了有多久
忘了有多久 2020-11-22 04:29

This may be a generic OOP question. I wanted to do a generic comparison between an interface and an abstract class on the basis of their usage.

When wou

相关标签:
23条回答
  • 2020-11-22 05:16

    An abstract class can have shared state or functionality. An interface is only a promise to provide the state or functionality. A good abstract class will reduce the amount of code that has to be rewritten because it's functionality or state can be shared. The interface has no defined information to be shared

    0 讨论(0)
  • 2020-11-22 05:17

    The answers vary between languages. For example, in Java a class can implement (inherit from) multiple interfaces but only inherit from one abstract class. So interfaces give you more flexibility. But this is not true in C++.

    0 讨论(0)
  • 2020-11-22 05:18

    Personally, I almost never have the need to write abstract classes.

    Most times I see abstract classes being (mis)used, it's because the author of the abstract class is using the "Template method" pattern.

    The problem with "Template method" is that it's nearly always somewhat re-entrant - the "derived" class knows about not just the "abstract" method of its base class that it is implementing, but also about the public methods of the base class, even though most times it does not need to call them.

    (Overly simplified) example:

    abstract class QuickSorter
    {
        public void Sort(object[] items)
        {
            // implementation code that somewhere along the way calls:
            bool less = compare(x,y);
            // ... more implementation code
        }
        abstract bool compare(object lhs, object rhs);
    }
    

    So here, the author of this class has written a generic algorithm and intends for people to use it by "specializing" it by providing their own "hooks" - in this case, a "compare" method.

    So the intended usage is something like this:

    class NameSorter : QuickSorter
    {
        public bool compare(object lhs, object rhs)
        {
            // etc.
        }
    }
    

    The problem with this is that you've unduly coupled together two concepts:

    1. A way of comparing two items (what item should go first)
    2. A method of sorting items (i.e. quicksort vs merge sort etc.)

    In the above code, theoretically, the author of the "compare" method can re-entrantly call back into the superclass "Sort" method... even though in practise they will never want or need to do this.

    The price you pay for this unneeded coupling is that it's hard to change the superclass, and in most OO languages, impossible to change it at runtime.

    The alternative method is to use the "Strategy" design pattern instead:

    interface IComparator
    {
        bool compare(object lhs, object rhs);
    }
    
    class QuickSorter
    {
        private readonly IComparator comparator;
        public QuickSorter(IComparator comparator)
        {
            this.comparator = comparator;
        }
    
        public void Sort(object[] items)
        {
            // usual code but call comparator.Compare();
        }
    }
    
    class NameComparator : IComparator
    {
        bool compare(object lhs, object rhs)
        {
            // same code as before;
        }
    }
    

    So notice now: All we have are interfaces, and concrete implementations of those interfaces. In practise, you don't really need anything else to do a high level OO design.

    To "hide" the fact that we've implemented "sorting of names" by using a "QuickSort" class and a "NameComparator", we might still write a factory method somewhere:

    ISorter CreateNameSorter()
    {
        return new QuickSorter(new NameComparator());
    }
    

    Any time you have an abstract class you can do this... even when there is a natural re-entrant relationship between the base and derived class, it usually pays to make them explicit.

    One final thought: All we've done above is "compose" a "NameSorting" function by using a "QuickSort" function and a "NameComparison" function... in a functional programming language, this style of programming becomes even more natural, with less code.

    0 讨论(0)
  • 2020-11-22 05:19

    For me, I would go with interfaces in many cases. But I prefer abstract classes in some cases.

    Classes in OO generaly refers to implementation. I use abstract classes when I want to force some implementation details to the childs else I go with interfaces.

    Of course, abstract classes are useful not only in forcing implementation but also in sharing some specific details among many related classes.

    0 讨论(0)
  • 2020-11-22 05:19

    Purely on the basis of inheritance, you would use an Abstract where you're defining clearly descendant, abstract relationships (i.e. animal->cat) and/or require inheritance of virtual or non-public properties, especially shared state (which Interfaces cannot support).

    You should try and favour composition (via dependency injection) over inheritance where you can though, and note that Interfaces being contracts support unit-testing, separation of concerns and (language varying) multiple inheritance in a way Abstracts cannot.

    0 讨论(0)
  • 2020-11-22 05:19

    An abstract class can have implementations.

    An interface doesn't have implementations, it simply defines a kind of contract.

    There can also be some language-dependent differences: for example C# does not have multiple inheritance, but multiple interfaces can be implemented in a class.

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