Question

After reading the most excellent book "Head First Design Patterns", I began proselytizing to my colleagues the benefits of patterns and design principles. While extolling the virtues of my favorite pattern - Strategy Pattern - I was asked a question which gave me pause. Strategy, of course, uses inheritance and composition and I was on one of my tirades about "program to an interface (or supertype) not an implementation", when a colleague asked "why use an abstract base class instead of a concrete class?".
I could only come up with "well you force your subclasses to implement abstract methods and prevent them from instantiating the ABC". But to be honest the question caught me off gaurd. Are these the only benefits of using an abstract base class over a concrete class at the top of my hierarchy?

Was it helpful?

Solution

If you need specific methods to be implemented, then use an Interface. If there is shared logic that can be pulled out, use an abstract base class. If the base set of functionality is complete on its own, then you can use a concreate class as the base. An abstract base class, and an Interface cannot be instantiated directly, and that is one of the advantages. If you can use a concrete type, then you need to do override methods, and that has a "code smell" to it.

OTHER TIPS

Program to interface, not to implementation has little to do with abstract and concrete classes. Remember the template method pattern? Classes, abstract or concrete, are the implementation details.

And the reason to use abstract classes instead of concrete classes is that you can invoke methods without implementing them, but by leaving them to be implemented to subclasses instead.

Programming to an interface is a different thing - it is defining what your API does, not how it does it. And this is denoted by interfaces.

Note one key difference - you can have protected abstract methods, which means that this is implementation detail. But all interface methods are public - part of the API.

Yes, although you could also use an interface to force a class to implement specific methods.

Another reason for using an abstract class as opposed to a concrete class is that an abstract class obviously can't be instantiated. Sometimes you also wouldn't want this to happen, so an abstract class is the way to go.

First of all, the Strategy Pattern should almost never be used in modern C#. It is mainly for languages like Java that don't support function pointers, delegates, or first-class functions. You will see it in older versions of C# in interfaces such as IComparer.

As for Abstract Base Class vs. Concrete Class, the answer in Java is always "What works better in this situation?" If your strategies can share code, then by all means let them do so.

Design patterns are not instructions on how to do something. They are ways to categorize things that we have already done.

Abstract base classes are usually used in scenarios where the designer wants to force an architectural pattern where certain tasks are to be carried out in the same manner by all the classes while other behaviours are dependent on the subclasses. example:

public abstract class Animal{

public void digest(){

}

public abstract void sound(){

}
}

public class Dog extends Animal{
public void sound(){
    System.out.println("bark");
}
}

Stratergy pattern asks designers to use Compositional behaviour for cases where there are families of alogirthms for a behaviour.

If the client relies on "implied behavior contract[s]", it is programmed against an implementation and against unguaranteed behavior. Overriding the method while following the contract only exposes bugs in the client, not causes them.

OTOH, the mistake of assuming contracts that aren't there is less likely to cause problems if the method in question is non-virtual--i.e., overriding it cannot cause problems because it cannot be overridden. Only if the implementation of the original method is changed (while still obeying the contract) can it break the client.

The question of whether a base class should be abstract or concrete depends IMHO largely on whether a base class object which implemented only behaviors that were common to all objects in the class would be useful. Consider a WaitHandle. Calling "wait" upon it will cause code to block until some condition is satisfied, but there's no common way of telling a WaitHandle object that its condition is satisfied. If one could instantiate a "WaitHandle", as opposed to only being able to instantiate instances of derived types, such an object would have to either never wait, or always wait forever. The latter behavior would be pretty useless; the former might have been useful, but could be achieved almost as well with a statically-allocated ManualResetEvent (I think the latter wastes a few resources, but if it's statically allocated the total resource loss should be trivial).

In many cases, I think my preference would be to use references to an interface rather than to an abstract base class, but provide with the interface a base class which provides a "model implementation". So any place one would use a reference to a MyThing, one would supply a reference to "iMyThing". It may well be that 99% (or even 100%) of iMyThing objects are actually a MyThing, but if someone ever needs to have an iMyThing object which inherits from something else, one could do so.

Prefer abstract base classes in below scenarios:

  1. A base class can't exist with out a sub class => the base class is simply abstract and it can' t be instantiated.
  2. A base class can't have full or concrete implementation of a method => Implementation of a method is base class is incomplete and only sub classes can provide complete implementation.
  3. Base class provides a template for method implementation but it still depends on Concrete class to complete the method implementation -Template_method_pattern

A simple example to illustrate above points

Shape is abstract and it can't exist without Concrete shape like Rectangle. Drawing a Shape can't be implemented at Shape class since different shapes have different formulas. The best option to handle scenario : leave draw() implementation to sub-classes

abstract class Shape{
    int x;
    int y;
    public Shape(int x,int y){
        this.x = x;
        this.y = y;
    }
    public abstract void draw();
}
class Rectangle extends Shape{
    public Rectangle(int x,int y){
        super(x,y);
    }
    public void draw(){
        //Draw Rectangle using x and y : length * width
        System.out.println("draw Rectangle with area:"+ (x * y));
    }
}
class Triangle extends Shape{
    public Triangle(int x,int y){
        super(x,y);
    }
    public void draw(){
        //Draw Triangle using x and y : base * height /2
        System.out.println("draw Triangle with area:"+ (x * y) / 2);
    }
}
class Circle extends Shape{
    public Circle(int x,int y){
        super(x,y);
    }
    public void draw(){
        //Draw Circle using x as radius ( PI * radius * radius
        System.out.println("draw Circle with area:"+ ( 3.14 * x * x ));
    }
}

public class AbstractBaseClass{
    public static void main(String args[]){
        Shape s = new Rectangle(5,10);
        s.draw();
        s = new Circle(5,10);
        s.draw();
        s = new Triangle(5,10);
        s.draw();
    }
}

output:

draw Rectangle with area:50
draw Circle with area:78.5
draw Triangle with area:25

Above code covers point 1 and point 2. You can change draw() method as template method if base class has some implementation and calls sub-class method to complete draw() function.

Now same example with Template method pattern:

abstract class Shape{
    int x;
    int y;
    public Shape(int x,int y){
        this.x = x;
        this.y = y;
    }
    public abstract void draw();

    // drawShape is template method
    public void drawShape(){
        System.out.println("Drawing shape from Base class begins");
        draw();
        System.out.println("Drawing shape from Base class ends");       
    }
}
class Rectangle extends Shape{
    public Rectangle(int x,int y){
        super(x,y);
    }
    public void draw(){
        //Draw Rectangle using x and y : length * width
        System.out.println("draw Rectangle with area:"+ (x * y));
    }
}
class Triangle extends Shape{
    public Triangle(int x,int y){
        super(x,y);
    }
    public void draw(){
        //Draw Triangle using x and y : base * height /2
        System.out.println("draw Triangle with area:"+ (x * y) / 2);
    }
}
class Circle extends Shape{
    public Circle(int x,int y){
        super(x,y);
    }
    public void draw(){
        //Draw Circle using x as radius ( PI * radius * radius
        System.out.println("draw Circle with area:"+ ( 3.14 * x * x ));
    }
}

public class AbstractBaseClass{
    public static void main(String args[]){
        Shape s = new Rectangle(5,10);
        s.drawShape();
        s = new Circle(5,10);
        s.drawShape();
        s = new Triangle(5,10);
        s.drawShape();
    }
}

output:

Drawing shape from Base class begins
draw Rectangle with area:50
Drawing shape from Base class ends
Drawing shape from Base class begins
draw Circle with area:78.5
Drawing shape from Base class ends
Drawing shape from Base class begins
draw Triangle with area:25
Drawing shape from Base class ends

Once you have decided that you have to make as method abstract, you have two options : Either user interface or abstract class. You can declare your methods in interface and define abstract class as class implementing the interface.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top