Please note that this article assumes you have read my previous tutorials on classes, and you know how to create an instance of a class.

Introduction

In my previous article, I mentioned that methods (functions defined in a given class) marked as public are the only methods visible to the entire program. On the other hand, methods that are marked as protected are accessible only within its class and derived class instances. In Object-Oriented Programming (OOP), abstraction is considered one of three fundamental principles (along with encapsulation and inheritance) that defines the OOP paradigm.

Through the use of abstraction, you can hide unwanted details of the underlying data about an object. This reduces complexity and – in some instances – increases efficiency. If you have a background in the arts, you will see some similarities. For instance, if you are sketching an apple, you may not sketch the unwanted details around the apple; the apple’s details are the only thing that really matters to you. In this way, an object created through a class represents the original, without the unwanted details. You can refer to the resulting object itself as an abstraction, or:

a named entity that is made up of selected attributes and behavior that is specific to a particular usage of the originating entity.

Abstraction is related to both encapsulation and data hiding. Through it, you can separate interface from implementation. It is often considered the most useful technique in data hiding. It is not just useful for the program where the design was originally implemented, but in other programs too. If you are creating a library that may be used by other programmers, it’s a very good basis for an API (Application Programming Interface). This is because it completely hides the implementation from the programmer. The users of your library won’t be distracted with the details of your magic methods; they will simply use them as a “black box” the way they were intended to be used. But how can we harness this awesome power of abstractness?

Even though the following source code examples may be valid for Java (or C++) too, I’m just focusing on C#. So, let’s get started!

Interfaces to the Rescue

Suppose you want to create a graphics library, whose sole purpose is to draw a simple circle or rectangle to a window. When you design the API with this in mind, your concern is not how the methods should be implemented, but how they will be used by a programmer. Through interfacing, you can separate the common methods of different classes; this assures that any class inheriting from the given interface must implement the methods defined in the interface. Let’s consider an interface Drawable, which has a method Draw. As mentioned previously, any classes that inherit the Drawable interface will need to implement a Draw function.

Every class that inherits from Drawable must implement Draw:

In this example, a programmer would not need to worry about any particular class’s implementation of Draw. Assuming the class implements the interface Drawable, the programmer would simply use those methods without worrying about the details of how they work behind-the-scenes. For easy readability and maintenance of your code, you should ensure that the method names are appropriate when compared to the interface (in this case, Drawable has an aptly-named Draw method.)

Additional Benefits

Libraries that you create and design around the concept of interfacing have other benefits as well. A programmer that uses your library can easily examine the interface, without having to understand the implementation. This alone enhances readability.

Abstractness can also increase the efficiency in some cases. Suppose you have several methods with similar Draw functionality, but you name them differently. For example, you may have Draw and DrawOnce, which (respectively) draw in a loop or draw a single time. The programmer can easily see how those methods are intended to be used. Conversely, if you use a boolean member in a class (for example alwaysDrawOnlyOnce), to flag whether the Draw method draws in a loop, it is a bit more confusing. There is a chance that a programmer may have had one too many drinks, and ends up writing an extremely inefficient game that draws the Heads-Up Display 60 times per second instead of 1.

Polymorphism

At this point, I should add that interfaces are related to the concept of polymorphism, or the application of interfaces. Polymorphism as a concept applies several sub-concepts, such as inheritance and generics. However, for the purposes of this article, I’m only focusing on its application of abstraction.

Through Polymorphism, a programmer can derive a class one step further, and use it in the place of a base class. In other words, it’s a way to generically use common methods.

In our example, any class (as long as it implements Drawable) can be passed to a Draw method. Here, the Draw method must belong to an instance of Window that implements the Drawable interface. This results in expressive code and reduced complexity (believe it or not).

Now, any programmer that wants to draw shapes other than rectangles and circles can create their own user-defined classes that inherit from Drawable. Then, they would simply implement the Draw method itself. As with the inputObject example above, the instance of a user-defined class can easily be passed into the Draw method of any Window instance. Through the process, we obtained what we wanted in the first place, i.e., data hiding… therefore, q.e.d., we can conclude that abstraction is indeed a great design for libraries.

Did this article encourage you to use abstraction in your next “killer” library? Do you have any questions or concerns about it? Please leave me your feedback in the comment section below, and I would be happy to help you in your programming journey!

Share

Comments are closed.

Post Navigation