Explaining Abstraction - One of the Basic Principals of OOP

alandevlin

Alan Devlin

Posted on October 23, 2022

Explaining Abstraction - One of the Basic Principals of OOP

Abstraction is one of the basic principals of Object-Oriented Programming, and one which is super easy to understand.

What exactly is Abstraction?

In a nutshell, abstraction involves hiding the complicated logic of an object from its users, and only providing the required inputs and outputs.

It's a very common practice, and one which every single software developer will have come across at some stage. I think we are all familiar with print('Hello World!)or console.log('Hello World!'). Its probably the first thing every developer learns, and it's a perfect example of abstraction usage. You don't need to know the inner details of how the print() function works here, but you just know that calling it while passing in a string will print the message. The hidden (and actually quite complex) logic of printing the string message is of no concern to the user and has been abstracted away from them.

Why use Abstraction?

The usage of abstraction and it's benefits are pretty clear from its definition - reducing complexity for users. Abstraction's key benefit is making our code simple and easy to use when implemented.
Abstraction is also important in the sense that it also allows users to implement more logic on top of an abstraction, without needing to think about all the hidden complexity.

When to use Abstraction?

Abstraction is most commonly used in two scenarios:

  1. When we want to share some common behavior
  2. Using the Template Method Pattern

Sharing common behavior is the most widely used usage of Abstraction. Lets take a look at how we can use abstraction in order to share common behaviour.

Example of Abstraction

Using TypeScript, I am going to create an abstract class called Vehicle which, when instantiated, will set the number of wheels and max speed of the object (in both km and miles). It also has three functions, one for returning the number of wheels, one for returning the max speed in km, and one for returning the max speed in miles.

abstract class Vehicle {
    private noWheels: number;
    private maxSpeed: number;
    private readonly KM_TO_MILE_CONVERSION = 1.609;

    constructor(noWheels: number, maxSpeedKilometers: number) {
        this.noWheels = noWheels;
        this.maxSpeed = maxSpeedKilometers;
    }

    public getNoWheels(): number {
        return this.noWheels;
    }

    public getMaxSpeedKilometers(): number {
        return this.maxSpeed;
    }

   public getMaxSpeedMiles(): number {
        return 
             parseFloat(
                    (this.maxSpeed/this.KM_TO_MILE_CONVERSION)
            .toFixed(2));
   }
}
Enter fullscreen mode Exit fullscreen mode

As you can see, the function for returning the max speed in miles has some additional logic tied to. We are diving the maxSpeed in km by the conversion number, before rounding the number to 2 decimal places, and parsing it back to float. In abstraction terminology, this is what we refer to as the "complicated logic", which abstraction is hiding from the end user.

Lets take a look at a child class, or a user of this abstract class below:

export class Car extends Vehicle {

    private carMake: string;

    constructor(numberOfWheels: number, maximumSpeed: number, 
                carMake: string){
        super(numberOfWheels, maximumSpeed);
        this.carMake = carMake;
        this.printMaxSpeedInMiles();
    }

    public printMaxSpeedInMiles(): void {
      // Max Speed of the Car in Miles from the Parent Object
      console.log('The Max Speed of the Car in Miles is: ' + 
      this.getMaxSpeedMiles());
    }
}
Enter fullscreen mode Exit fullscreen mode

We can see that this class utilizes the abstract class due to the use of the implements keyword. This, alongside calling the super() method, gives us access to the abstract classes functions. We can see this by the fact that within printMaxSpeedInMiles() we are able to call the Vehicle function getMaxSpeedMiles(), without defining it ourselves.

What this all means is that if we then instantiate a new object of type Car:
new Car(2, 175, 'hyundai');

We will automatically get the max speed per miles printed to the console:
The Max Speed of the Car in Miles is: 108.76

The benefit here, of course, is that we can have multiple 'child' classes which are abstracted from Vehicle. We could have a class Bicycle or Motorcyle and we would also have the ability to retrieve the max speed of either in km or miles, alongside adding additional functionality on top of this. Of course, this is a very basic example, but hopefully you get the picture.

So there you have it, a basic example of one of the key principals of OO Programming - Abstraction

💖 💪 🙅 🚩
alandevlin
Alan Devlin

Posted on October 23, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related