37

I used to create a lot of abstract classes / methods. Then I started using interfaces.

Now I am not sure if interfaces aren't making abstract classes obsolete.

You need a fully abstract class? Create an interface instead. You need an abstract class with some implementation in it? Create an interface, create a class. Inherit the class, implement the interface. An additional benefit is that some classes may not need the parent class, but will just implement the interface.

So, are abstract classes / methods obsolete?

  • How about if your programming language of choice does not support interfaces? I seem to recall this is the case for C++. – Bernard Jul 21 '11 at 15:48
  • 7
    @Bernard: in C++, an abstract class is an interface in all but name. That they can also do more than 'pure' interfaces is not a disadvantage. – gbjbaanb Jul 21 '11 at 15:51
  • @gbjbaanb: I suppose. I don't recall using them as interfaces, but rather to provide default implementations. – Bernard Jul 21 '11 at 16:01
  • Interfaces are the "currency" of object references. Generally speaking they are the fundament of polymorphic behavior. Abstract classes serve a different purpose that deadalnix explained perfectly. – jiggy Jul 21 '11 at 16:56
  • 4
    Isn't this like saying "are modes of transport obsolete now we have cars?" Yeah, most of the time, you use a car. But whether you ever need anything other than a car or not, it wouldn't really be correct to say "I don't need to use modes of transport". An interface is much the same as an abstract class without any implementation, and with a special name, no? – Jack V. Jul 22 '11 at 9:11

11 Answers 11

111

No.

Interfaces cannot provide default implementation, abstract classes and method can. This is especially usefull to avoid code duplication in many cases.

This is also a really nice way to reduce sequential coupling. Without abstract method/classes, you cannot implement template method pattern. I suggest you look at this wikipedia article : http://en.wikipedia.org/wiki/Template_method_pattern

  • 3
    @deadalnix Template method pattern can be quite dangerous. You can easily end up with highly coupled code, and start hacking the code to extend the templated abstract class to handle "just one more case". – quant_dev Jul 21 '11 at 17:20
  • 9
    This seems more like an anti-pattern. You can get exactly the same thing with composition against an interface. Same thing applies to partial classes with some abstract methods. Rather then forcing client code to subclass and override them, you should have the implementation be injected. See: en.wikipedia.org/wiki/Composition_over_inheritance#Benefits – back2dos Jul 21 '11 at 21:17
  • 4
    This doesn't explain AT ALL how to reduce sequential coupling. I do agree that several ways exists to achieve this goal, but please, answer the problem you are talking about instead of blindly invoke some principle. You'll ends up doing cargo cult programming if you can't explain why this is related to the actual problem. – deadalnix Jul 21 '11 at 21:27
  • 3
    @deadalnix: Saying that sequential coupling is best reduced with the template pattern is cargo cult programming (using the state/strategy/factory pattern may just work as well), as is the assumption that it must always be reduced. Sequential coupling is often a mere consequence of exposing very fine grained control over something, meaning nothing but a trade-off. That still doesn't mean I can't write a wrapper that does not have sequential coupling using composition. In fact, it makes it a lot easier. – back2dos Jul 22 '11 at 7:30
  • 4
    Java now has default implementations for interfaces. Does that change the answer? – raptortech97 Oct 20 '14 at 12:32
15

An abstract method exists so you can call it from within your base class but implement it in a derived class. So your base class knows:

public void DoTask()
{
    doSetup();
    DoWork();
    doCleanup();
}

protected abstract void DoWork();

That's a reasonably nice way to implement a hole in the middle pattern without the derived class knowing about the setup and cleanup activities. Without abstract methods, you'd have to rely on the derived class implementing DoTask and remembering to call base.DoSetup() and base.DoCleanup() all the time.

Edit

Also, thanks to deadalnix for posting a link to the Template Method Pattern, which is what I've described above without actually knowing the name. :)

  • 2
    +1, I prefer your answer to deadalnix'. Note that you can implement a template method in a more straight-forward way using delegates (in C#): public void DoTask(Action doWork) – Joh Jul 25 '11 at 9:09
  • 1
    @Joh - true, but that's not necessarily as nice, depending on your API. If your base class is Fruit and your derived class is Apple, you want to call myApple.Eat(), not myApple.Eat((a) => howToEatApple(a)). Also, you don't want Apple to have to call base.Eat(() => this.howToEatMe()). I think it's cleaner just to override an abstract method. – Scott Whitlock Jul 25 '11 at 14:03
  • 1
    @Scott Whitlock: Your example using apples and fruits is a bit too detached from reality to judge whether going for inheritance is preferable to delegates in general. Obviously, the answer is "it depends", so it leaves plenty of room for debates... Anyway, I find that template methods occur a lot during refactoring, e.g. when removing duplicate code. In such cases, I usually don't want to mess with the type hierarchy, and I prefer to stay away from inheritance. This kind of surgery is easier to do with lambdas. – Joh Jul 27 '11 at 10:18
  • This question illustrates more than a simple application of the Template Method pattern - the public/non-public aspect is known in the C++ community as the Non Virtual Interface pattern. By having a public non-virtual function wrap the virtual one - even if initially the former does nothing but call the latter - you leave a point of customisation for setup/cleanup, logging, profiling, security checks etc. that might be needed later. – Tony May 10 '14 at 2:27
10

No, They are not obsolete.

In fact, there is an obscure but fundamental difference between Abstract Classes/Methods and Interfaces.

if the set of classes in which one of these has to be used have a common behaviour that they share (related classes, i mean), then go for Abstract classes/methods.

Example: clerk, Officer, Director -all these classes have CalculateSalary() in common, use abstract base classes.CalculateSalary() canbe differently implemented but there are certain other things like GetAttendance() for example which has a common definition in base class.

If your classes have nothing common(Unrelated classes, in the context chosen) in between them but has an action that is greatly different in implementation, then go for Interface.

Example: cow, bench, car, telesope-not related classes but Isortable can be there to sort them in an array.

This difference is usually ignored when approached from a polymorphic perspective. But I personally feel that there are situations where one is an apt than the other for the reason explained above.

6

In addition to the other good answers, there is a fundamental difference between interfaces and abstract classes that no one has mentioned specifically, namely that interfaces are far less reliable and therefore impose a much greater test burden than abstract classes. For example, consider this C# code:

public abstract class Frobber
{
    private Frobber() {}
    public abstract void Frob(Frotz frotz);
    private class GreenFrobber : Frobber
    { ... }
    private class RedFrobber : Frobber
    { ... }
    public static Frobber GetFrobber(bool b) { ... } // return a green or red frobber
}

public sealed class Frotz
{
    public void Frobbit(Frobber frobber)
    {
         ...
         frobber.Frob(this);
         ...
    }
}

I am guaranteed that there are only two code paths I need to test. The author of Frobbit can rely on the fact that the frobber is either red or green.

If instead we say:

public interface IFrobber
{
    void Frob(Frotz frotz);
}
public class GreenFrobber : IFrobber
{ ... }
public class RedFrobber : Frobber
{ ... }

public sealed class Frotz
{
    public void Frobbit(IFrobber frobber)
    {
         ...
         frobber.Frob(this);
         ...
    }
}

I now know absolutely nothing about the effects of that call to Frob there. I need to be sure that all the code in Frobbit is robust against any possible implementation of IFrobber, even implementations by people who are incompetent (bad) or actively hostile to me or my users (far worse).

Abstract classes allow you to avoid all these problems; use them!

  • 1
    The problem you speak of should be solved by using algebraic data types, rather than bending classes to a point where they violate the open/closed principle. – back2dos Jul 21 '11 at 21:58
  • 1
    Firstly, I never said it is good or moral. You put that in my mouth. Secondly (being my actual point): It's nothing but a poor excuse for a missing language feature. Lastly, there's a solution without abstract classes: pastebin.com/DxEh8Qfz. In contrast to that, your approach uses nested and abstract classes, throwing all but the code requiring the safety together into a big ball of mud. There is no good reason why RedFrobber or GreenFrobber should be tied to the constraints you want to enforce. It increases coupling and locks in many decisions without any benefit. – back2dos Jul 22 '11 at 7:17
  • 1
    Saying that abstract methods are obsolete is wrong with no doubt, but claiming on the other hand that they should be preferred over interfaces is misguiding. They are simply a tool for solving different problems than interfaces. – Groo Jul 22 '11 at 9:37
  • 2
    "there is a fundamental difference [...] interfaces are far less reliable [...] than abstract classes". I disagree, the difference you have illustrated in your code relies on access restrictions, which I don't think have any reason to differ significantly between interfaces and abstract classes. It may be so in C#, but the question is language-agnostic. – Joh Jul 25 '11 at 9:15
  • 1
    @back2dos: I'd just like to point out that Eric's solution does, in fact, use an algebraic data type: an abstract class is a sum type. Calling an abstract method is the same as pattern matching over a set of variants. – Rodrick Chapman Aug 1 '11 at 23:30
4

You say it yourself:

You need an abstract class with some implementation in it? Create an interface, create a class. Inherit the class, implement the interface

that sounds a lot of work compared to 'inherit the abstract class'. You can make work for yourself by approaching code from a 'purist' view, but I find I have enough to do already without trying to add to my workload for no practical benefit.

  • Not to mention that if the class doesn't inherit the interface (which was not mentioned it should), you have to write forwarding functions in some languages. – Sjoerd Jul 21 '11 at 17:25
  • Umm, the additional "Lot of work" you mentioned is that you created an interface and had the classes implement it--does that really seem like a lot of work? On top of that, of course, the interface gives you the ability to implement the interface from a new hierarchy which wouldn't work with an abstract base class. – Bill K Dec 20 '11 at 21:11
4

As I commented on @deadnix post: Partial implementations are an anti-pattern, despite the fact that template pattern formalizes them.

A clean solution for this wikipedia example of the template pattern:

interface Game {
    void initialize(int playersCount);
    void makePlay(int player);
    boolean done();
    void finished();
    void printWinner();
}
class GameRunner {
    public void playOneGame(int playersCount, Game game) {
        game.initialize(playersCount);
        int j = 0;
        for (int i = 0; !game.finished(); i++)
             game.makePlay(i % playersCount);
        game.printWinner();
    }
} 
class Monopoly implements Game {
     //... implementation
}

This solution is better, because it uses composition instead of inheritance. The template pattern introduces a dependency between the implementation of the Monopoly rules and the implementation of how games are to be run. However these are two entirely different responsibilities and there is no good reason to couple them.

  • +1. As a side-note: "Partial implementations are an anti-pattern, despite the fact that template pattern formalizes them.". The description on wikipedia defines the pattern cleanly, only the code example is "wrong" (in the sense that it uses inheritance when it's not needed and a simpler alternative exists, as illustrated above). In other words, I don't think the pattern itself is to blame, only the way people tend to implement it. – Joh Jul 25 '11 at 9:21
2

No. Even your proposed alternative includes the use of abstract classes. In addition, since you didn't specify the language, then I'm going to go right ahead and say that generic code is the better option than brittle inheritance anyway. Abstract classes have significant advantages over interfaces.

  • -1. I don't understand what "generic code vs inheritance" has to do with the question. You should illustrate or justify why "abstract classes have significant advantages over interfaces". – Joh Jul 25 '11 at 9:25
1

Abstract classes are not interfaces. They're classes that can't be instantiated.

You need a fully abstract class? Create an interface instead. You need an abstract class with some implementation in it? Create an interface, create a class. Inherit the class, implement the interface. An additional benefit is that some classes may not need the parent class, but will just implement the interface.

But then you would have a non-abstract useless class. Abstract methods are required to fill in functionality hole in the base class.

For example, given this class

public abstract class Frobber {
    public abstract void Frob();

    public abstract boolean IsFrobbingNeeded { get; }

    public void FrobUntilFinished() {
        while (IsFrobbingNeeded) {
            Frob();
        }
    }
}

How would you implement this base functionality in a class that has neither Frob() nor IsFrobbingNeeded?

  • 1
    An interface can't be instantiated either. – Sjoerd Jul 21 '11 at 17:22
  • @Sjoerd: But you need a base class with the shared implementation; that can't be an interface. – configurator Jul 21 '11 at 17:58
1

I am a creator of servlet framework where abstract classes play essential role. I would say more, I need semi abstract methods, when a method needs to be overridden in 50% cases and I would like to see warning from compiler about that method wasn't overridden. I resolve the problem adding annotations. Returning back to your question, there are two different use case of abstract classes and interfaces, and no one is obsolete so far.

0

I don't think they're obsoleted by interfaces, but they might be obsoleted by the strategy pattern.

The primary use of an abstract class is to postpone a part of the implementation; to say, "this part of the class's implementation can be made different".

Unfortunately, an abstract class forces the client to do this via inheritance. Whereas the strategy pattern will allow you to achieve the same result without any inheritance. The client can make instances of your class rather than always defining their own, and the class's "implementation" (behaviour) can vary dynamically. The strategy pattern has the additional plus that behaviour can be changed at run-time, not only at design-time, and also has significantly weaker coupling between the types involved.

0

I've generally faced far, far, more maintenance problems associated with pure interfaces than ABCs, even ABCs used with multiple inheritance. YMMV -- dunno, maybe our team just used them inadequately.

That said, if we use a real world analogy, how much use is there for pure interfaces completely devoid of functionality and state? If I use USB as an example, that's a reasonably stable interface (I think we're at USB 3.2 now, but it has also maintained backwards compatibility).

Yet it's not a stateless interface. It's not devoid of functionality. It's more like an abstract base class than a pure interface. It's actually closer to a concrete class with very specific functional and state requirements, with the only abstraction being what plugs into the port being the only substitutable part.

Otherwise it would just be a "hole" in your computer with a standardized form factor and much looser functional requirements which wouldn't do anything on its own until every manufacturer came up with their own hardware to make that hole do something, at which point it becomes a much weaker standard and nothing more than a "hole" and a specification of what it should do, but no central provision for how to do it. Meanwhile we might end up with 200 different ways to do it after all hardware manufacturers try to come up with their own ways to attach functionality and state to that "hole".

And at that point we might have certain manufacturers that introduce different problems over others. If we need to update the specification we might have 200 different concrete USB port implementations with totally different ways of tackling the specification having to be updated and tested. Some manufacturers might develop de facto standard implementations they share amongst themselves (your analogical base class implementing that interface), but not all. Some versions might be slower than others. Some might have better throughput but worse latency or vice versa. Some might use more battery power than others. Some might flake out and not work with all hardware that's supposed to work with USB ports. Some might require a nuclear reactor to be attached to operate which has a tendency to give its users radiation poisoning.

And that's what I've found, personally, with pure interfaces. There might be some cases where they make sense, like just to model the form factor of a motherboard against a CPU case. Form factor analogies are, indeed, pretty much stateless and devoid of functionality, as with the analogical "hole". But I often consider it a huge mistake for teams to consider that to be somehow superior in all cases, not even close.

To the contrary, I think far more cases would be solved better by ABCs than interfaces if those are the two choices unless your team is so gigantic that it's actually desirable to have the analogical above equivalent of 200 competing USB implementations rather than one central standard to maintain. In a former team I was in, I actually had to fight hard just to loosen up the coding standard to allow ABCs and multiple inheritance, and mainly in response to these maintenance problems described above.

protected by gnat Oct 20 '14 at 11:39

Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).

Would you like to answer one of these unanswered questions instead?

Not the answer you're looking for? Browse other questions tagged or ask your own question.