Interfaces – The quest for re-use. [Part 1 – Concrete class]

The quest for re-use is obviously not a software engineering creation; it is a pretty common and sought after property in many fields. In the software world this should equate to a saving of resources (time, money and risk) when used properly. When you are re-using pieces of code, you are saving the development time and thus money and testing.

To achieve re-use of software there are multiple options available. Two of the main contenders are inheritance and polymorphism (which you can achieve with interfaces). It is crucial to decide before hand, which type of design you will use to achieve this.

So not losing sight of the main reason of wanting to achieve re-use, let’s start by looking at the options. We will be illustrating this by means of a comparison between: concrete, abstract classes and of course the interface.

To illustrate the pros and cons between these types, the very common, example of polygons will be used. It seems more like a geometry lesson at first but it illustrates the point quite well – so press on through. Remember the goal – to achieve re-use in the most optimal way!

Regular polygons

What are regular polygons? These are geometrical shapes that have:

  • 3 or more sides.
  • All the sides having the same length.

Triangle_and_Squere

So let’s say you have to write a program and within this program the aim is to generically handle and display certain data from different types of polygons.

The first step is to have a close look at the object types that we are going to handle and abstract the common characteristics to a base class. The concept of Abstraction , is a broad topic in itself but it boils down to: The process of taking away or removing characteristics from something in order to reduce it to a set of essential characteristics. In object-oriented programming, abstraction is one of three central principles (along with encapsulation and inheritance). Through the process of abstraction, a programmer hides all but the relevant data about an object in order to reduce complexity and increase efficiency. [http://whatis.techtarget.com/definition/abstraction]

When abstracting the common characteristics we should end up with:

  1. Both shapes have a number of sides.
  2. Both shapes have sides with known lengths.

Now knowing this we can create a base class that depicts these characteristics,we will make use of the following 2 fields:

private int numberOfSides;

private int lengthOfSides;

So in order to make our more class functional, we will add two methods to it. They will do the following:

  1. Calculate the perimeter of the shape i.e. the length of the outer sides added together. This should not prove to be very difficult as we already have all the necessary data to calculate this. As all sides are of the same length (definition of a polygon), we would thus only need to multiply the number of sides with the length of the sides!

  Perimeter = Number of Sides x Side Length

  1. Calculate the area of the a shape.

Polygon-Area-Calc

The building of this functionality culminates in a base class that can handle all the abstracted characteristics of the polygons. A consumer class will inherit from this base class. By doing this you will then have access to the base class’s functionality, in turn you will be re-using code.

Maybe you noticed it, but at point 2 (the area-calculation) it becomes clear that we have a bit of a problem. Calculating the area gets a bit more tricky and we bump into the reason for this tedious geometry lesson!

From point 2 it is clear that there is no generic way to handle the area-calculation. Meaning we cannot create a class that we can use (instantiate) for all types of objects (polygons like the triangle and the square) as the area calculation formula differs per polygon type. I suppose one could argue that you can try and distill what type of polygon you are dealing with, but that would just over complicate things and be in direct conflict with good object-orientated design principles. This implies that the object type that gets instantiated will have to specify its own very specific way of calculating its area. The correct term to use here would be that this function needs to be overridden. We are leaving the task of filling in the area calculation to the consumer of this class.

So to solve this problem in code we can make use of three illustrations:

  1. By making use of a concrete class and specifying the virtual keyword.
  2. By making use of an abstract class and specifying the abstract keyword.
  3. By making use of Interfaces.

As seen in the theory described above the crux of the matter is solving the problem of the area calculation. The reason for this is that the child class needs to handle this on its own; it cannot be handled in a generic way. The way we will achieve this in the concrete class scenario is by the following the example of a Concrete Library Class depicting a Regular Polygon.

Concrete class:

A concrete class is a class that can be instantiated, as opposed to abstract classes, which cannot. It is your very basic edition in the class types. The overriding functionality (that enable child classes to override certain functions) is achieved by marking the method as virtual in the method definition. The “GetArea” method will be marked as virtual to enable the child classes to override this function and supply their own custom implementation of it.

Snap 2015-08-14 at 14.52.08

The important part to take note of here is the GetArea() method marked in the red square. This method cannot be implemented in the Concrete Class as the implementation depends on the number of sides of the polygon. It is thus up to the child class to override this functionality.

So let’s look at a class that will make use of this base class. Take the square class for example:

Snap 2015-08-24 at 22.00.33

Notice that the new consumer class, in this case Square inherits from ConcreteRegularPolygon. This is indicated by the double colon : sign. You can see that the area calculation routine is specified, in this case specifically for a Square.

Perimeter = Number of Sides x Side Length

Now let’s have a look at the client that will use the Square class:

Snap 2015-08-25 at 21.45.08

When running the code above the following output will be rendered:

Output-Concrete-Sqaere

All works as expected! But let’s try and comment out the override function and compile the Square class and see what happens…

Polygon-concrete-comment-out-Calc

Strangely enough you will notice that the code still compiles! Why? Why does the compiler not check that the function exists??

Running the code delivers some totally different results! The code crashes for an Not implemented exception when the GetArea() method is executed. This exception was explicitly included into our base class design (see the base class code) as we wanted clients to override the function and be “notified” when not doing so.

You could maybe argue that you can limit this strange behavior by opting for a hard coded value like 0 (zero) in stead. It would however give a false positive when the consumer class “forgets” to override the function and then gets the default value. This is not advisable.

Output-Concrete-Sqaere-Exception

So to summarize the code re-use progress:

Re-use is possible, however it lacks compile time checking on the implementation of virtual members which should be done in the child classes.

The implementation of virtual members in the child classes is the responsibility of the developer. If you forget to do this it results in a RUNTIME ERROR!

In the next section we will have a look at achieving code re-use by making use of an abstract class.

Leave a comment