Introduction

OOP (stands for Object Oriented Programming) is a programming paradigm. It was invented by Alan Kay in 1966. One can think of Objects in OOP as Objects in real life.

To explain what OOP is all about let’s take an example about cars.

Example: Cars

In real life, a car has properties & methods. A property is some attribute for a car, its color for example. While a method is some functionality of a car (e.g. The car moves).

The car also interacts with other objects, for instance the driver is one who moves the car. The driver can be though of as another object.

Do you understand so far? Great, let’s see how this translates to code.

While writing programs, We have many objects much like the real life, the object can be based on a real life object (e.g. You’re building a Car racing game, so you have some car objects) or it can be a concept (e.g. an ArrayBuffer). In software, an object can be anything.

Before we dive into the code, remember there’re other programming paradigms out there like Functional Programming, Procedural Programming, ..etc.

Note: I’m using Java since I believe it’s a better to choice for explaining OOP given its verbosity , high level & popularity.

Another Note: This is not a Java Tutorial.

class Driver {
  // Properties
  String name;
  int age;

  // Constructor
  public Driver(String name, int age) {
    this.age = age;
    this.name = name;
  }

  // Method
  public void driveTo(int x, int y) {
    //Do something...
  }

  public String getName() {
    return this.name;
  }

}

class Car {
  // Properties
  String color;
  String model;
  Driver driver;

  // Constructor
  public Car(String color, String model, Driver driver) {
    this.driver = driver;
    this.model = model;
    this.color = color;
  }

  // Method
  public void move(int x, int y) {
    this.driver.driveTo(x, y);
  }

  public String getDriverName() {
    return this.driver.getName();
  }
}

Now we have 2 classes, each represents a class of objects the Car class represents all Cars our world & the driver class represents all Drivers in our world.

You can see the difference between a property & a method now, but what is the constructor?

Simply a put a constructor is responsible for creating an object from such class (Remember a Car class represents all cars in our world not just one).

Now we can use both of our classes to create objects like this

class MyProgram {
  public static void main(String[] args) {

    //instantiates a driver with name John Doe & age 38 
    Driver johnDoe = new Driver("John Doe", 38);
    // We can now use all methoids in the johnDoe object
    // Ex. johnDoe.getName();

    Car fordFiesta = new Car("Blood Red", "Ford Fiesta", johnDoe);

    // This shoud print: John Doe
    System.out.println(fordFiesta.getDriverName());
  }
}

Now we know have an idea about OOP, we know what a class is & what an Object is.

Let’s see why would you use it in first place.

Note: I’m not a fan of a single programming paradigm, if it suits the application & business needs then it’s ok. (I prefer FP anyway)

Reasons to use OOP

  1. Simplicity

OOP is one of the simplest Programming paradigms in software (in terms of written code). It’s modular by nature. People know it very well & it’s easy to understand.

  1. Market Offerings

Not all devs like to right FP or something other than OOP, most people knows it & people can pick it up in a matter of hours.

  1. The type of your application

If you’re building an application, most propaply OOP will be ok for your use case in terms of performance, productivity & cleanliness.

  1. Clean Code

No I’m not talking about the SOLID principles…

By nature, OOP code is reusable and modular which makes it easier to write clean code.

The Four principles of OOP

OOP has 4 pillars which are: Abstraction, Encapsulation, Inheritance & Polymorphism

1. Abstraction

Abstraction is the idea of hiding implementation details (how something works).

The next example is taken from FreeCodeCamp

Let’s take an example to better understand it. Let’s say you want to build a coffee machine. A simple design is to have a button that says “Make coffee” (Here you’re hiding how a coffee is made) Another design would be having 5 buttons like so:

  1. Boil Water
  2. Put coffee in correct place
  3. Pour water through coffee

This also translates to code where we might have a complex operation (e.g. caculating the square root of a number). An abstract way is to provide a method or a function called getSqureRoot. A non abstract way is to provide 3 methods:

This assumes that you’re going to do it the Babylonian way

  1. getInitialGuess
  2. improveGuess
  3. loopUntilConvergence

The user of your library would then call the loopUntilConvergence passing to it the initial guess and how to improve the guess.

P.S. Check this video by Hussein Nasser talking about Leaky Abstractions

2. Encapsulation

Similar to Abstraction, encapsulation hides data (not implementation detail). Which is why we have some cool language constructs like private, protected, & public So we can specify who is able to see such data. In Encapsulation, you generally remove unneeded access to your objects’ properties & methods.

Encapsulation is also known as data hiding

3. Inheritance

Inheritance is reusing & extending your class by adding a sub-class that is based on the earlier class. This means that (without any modification) if you make a class inherit another class it’ll be the same class.

You can then make modification to the new class to extend the functionality of the base class.

Looking at our car example, let’s say that we have a third class called Vehicle and a fourth one called Tractor A sane approach would be having both the Car & Tractor inherit from Vehicle given that they have pretty much the same base attributes.

Here’s an updated version the above example:

// Class Vehicle is the same as the previous Class car
class Vehicle {
  // Properties
  String color;
  String model;
  Driver driver;

  // Constructor
  public Vehicle(String color, String model, Driver driver) {
    this.driver = driver;
    this.model = model;
    this.color = color;
  }

  // Method
  public void move(int x, int y) {
    this.driver.driveTo(x, y);
  }

  public String getDriverName() {
    return this.driver.getName();
  }
}
class Car extends Vehicle {
  // Extra Properties
  bool isFourWheelsDrive;

  // Constructor
  public Car(bool isFourWheelsDrive, String color, String model, Driver driver) {
    // Call the Vehicle constructor
    this.super(color, model, driver);
    this.isFourWheelsDrive = isFourWheelsDrive;
  }

  // Extra Method
  public String getInfo() {
    // We can access the base class properties & methods
    return this.driver.getDriverName();
  }
}

4. Polymorphism

The word “Polymorphism” means the ability for something take multiple shapes. In code, this translates to something we call Generics Generics allow us to create a single function for multiple types. For example, let’s say we need to implement a function that prints all driver info from all Vehicles. But the thing is, A car is a vehicle, a tractor is vehicle & so on. How would we write such function? Easy peasy lemon squeezy, Remember that all Cars & Tractors inherit from the class Vehicle? We can then use this type as our argument and write our function like this:

  public void printAllNames(Vehicle[] vehicles) {
    for (int i = 0; i < vehicles.length; i++) {
      //Since we're using a method that exists on the base class,
      //we're sure that all given entries have this method.
      vehicles[i].getDriverName();
    }
  }

  // And then we can call it like this:
  printAllNames([new Car(...), new Tractor("..."), new Vehicle("...")]);