Object Oriented Programming Paradigm

Object Oriented Programming Paradigm

Time to add another post under Programming Paradigms and here, let’s talk about Object Oriented Programming Paradigm. But before that, optionally, take a look at Imperative Programming Paradigm for more context.

What is Object Oriented Programming?

One of the most commonly used paradigm out there today is the Object Oriented Programming Paradigm (OOPP). An object is something bundles data and procedures within itself. Objects are the protagonist in this paradigm. The program is revolves around objects where the programmer writes code to create objects and tell them how to communicate with each other. This interaction between objects changes the state of the program eventually leading to the end result.

How does Object Oriented Programming work?

In OOPP, objects are modeled based on real-world entities. Just like how real-world entities interact with each other, the objects in an application communicates between each other. By interacting, real-world entities reach the final state and similarly, by communicating, the objects change the state of the application, eventually achieving the final result.

Modification of program state by the interactions and communications between objects to get the end result is the OOP style of programming.

Class-based and Prototype-based OOPP

In OOPP, objects are the protagonists and there are two ways to create objects. This is based on the style of programming dividing OOPP into two sub-paradigms.

  • Class-based programming
  • Prototype-based programming
Different styles of Object Oriented Programming

If you have worked with Java, then you must be familiar with classes. Similarly, if you have worked with JavaScript, then you must be familiar with prototypes.

Class-based programming

In class-based programming, classes defines the structure of objects, i.e., it defines what variables and procedures should an object hold. An object created for a class will have it’s own identity and becomes an instance of the class. I’ll be talking more about class in under building blocks of OOPP.

Prototype-based programming

Prototype-based programming works by cloning and extending existing objects and there is no concept of class. Inheritance is by reusing existing objects that serves as prototypes.

Now, let’s dive deeper into OOPP. For this post, I’ll explain OOPP with examples based on class-based programming using Java since I have future plans for prototype-based programming.

Just a meme of me thinking
le me with plans

Building Blocks of Object Oriented Programming

There are 4 building blocks for OOPP.

  1. Class
  2. Object
  3. Attribute
  4. Procedure

Class

As discussed earlier, a class is a blueprint that defines the structure of an object. By structure, I mean details like what data should the object hold and what procedures it can perform.

Let’s design a class for a real-world object. The below is the code to design a class for Car.

class Car {
    String model;
    String manufacturer;
    String color;
    boolean isDoorOpen;

    void openDoor() {
        this.isDoorOpen = true;
    }
    
    void closeDoor() {
        this.isDoorOpen = false;
    }

    void drive(String destination) {
        // do some driving
    }
}

Here, Car is a blueprint that defines the structure of a car object. It defines what attributes and procedures that the object should have. This makes the code more reusable since I can create n number of objects for this blueprint. Reusability is one of the virtues of OOPP. Note that while a real-world entity can have any number of attributes and can perform any number of actions, we do not have to model classes with all the attributes and actions. It is a good practice to design objects with data and procedures that are just enough for the application.

Object

In general, an object is a variable in the memory. In addition to that, in OOPP, an object contains a set of attributes (variables) and procedures (methods). The structure of an object is based on the class in class-based programming. The beauty is, the object can use it’s procedures to modify it’s attributes. Such modifications changes it’s state, eventually, leading to the end result. This makes OOPP stateful.

This is an Object in object oriented programming
An object

Usually in OOPP, objects are used to model real world elements. In a different perspective, we can say that our world is one giant application where everything in it are objects, including us. If we are objects, data like our name, age, gender, address, college degree becomes our attributes and our actions like walk, talk, run becomes our procedures. In a computer program, we can model objects based anything in the real-world.

Car carOne = new Car();         // created new object carOne
// Setting the state of the object.
carOne.model = "Carrera GT";
carOne.manufacturer = "Porsche";
carOne.color = "Guards Red";
carOne.numberOfSeats = 2;

In the above example, I created an object carOne for our class Car and set values to the attributes of the object. This sets up a state for the object. Now we know details of the car through these attributes. With the class Car as a blueprint, any number of objects with it’s own version of attributes and procedures can be created.

Car as class and objects in object oriented programming
Image credits: https://stackoverflow.com/questions/2885385/

Note that we are using the dot operator on the variable to access it’s attributes. An object’s attributes and procedures can be accessed only by using the dot operator.

The dot operator, also known as separator or period used to separate a variable or method from a reference variable.

What is an instance?

The English dictionary says, an instance is single occurrence of something. In programming, an instance is a single occurrence of a class. Technically, an instance is an object. While objects refer to all the objects in general, an instance refers to a specific representation of an object. Like our class Car, we can create several other classes like Plane, Boat, Bike, etc. Each of these classes can have many number of objects. Regardless of the class, all the objects are termed as “objects”. But from our previous example, carOne is an object but an instance of Car.

In the previous example, I created the object carOne using the new keyword and assigned the newly created object to the variable carOne by using = operator. By using new keyword, we create a new “instance” of the class Car, allocating memory to the instance. Memory to an instance is allocated only when it is created. This process is called instantiating a class. Based on the variables bundled inside, the memory size of an instance varies.

Each instance is unique and has it’s own place in the memory having it’s own version of attributes and procedures.

Car carOne = new Car();
carOne.model = "Carrera GT";

Car carTwo = new Car();
carOne.model = "Gallardo";

Car carThree = new Car();
carOne.model = "Mustang";

In the above example, we create 3 instances, carOne, carTwo and carThree, for the class Car. Each object will have it’s own version of the attribute model.

Memory example of cars
This is not the actual memory allocation. Image is only for visual understanding.

The above image is a rough representation of how these objects will be in the memory. When an instance is created, the variables inside the instance are also instantiated and allocated memory. When I access the variable model bundled inside carOne with the statement carOne.model, the program will navigate through the addresses to get the actual value. For the statement carOne.model, the value at address 300 is accessed since the model bundled inside carOne points to 300 but it cannot access 301 since it belongs to carTwo.

The keyword “this”

An object to refers to itself by using this keyword.

class Car {
    private String color;

    public void setColor(String color) {
        color = color;          // The variable color is in the procedure's scope. This doesn't work.
        this.color = color;     // 'this.color' is the instance level variable and 'color' is in method's scope
    }
}

In the above example, I’m trying to assign the value to the attribute color in the procedure setColor. Note that there are two variables with same name color in this procedure. Since we have two variables with same name, the first statement color = color will not work. The operands in both the sides are same variable, we are just assigning the value of color to itself. This is because, the scope of the variable color in this line is within this method and it will not exist outside this method. To assign the value to the instance level attribute, we should use the statement in the second line. In the statement this.color = color, we are referring to the object’s attribute color by using this keyword. The operand of the left is the instance level attribute while the operand on the right is the method level attribute.

Ok, now that’s enough about objects. Let’s move forward.

Attribute

Attributes are variables inside an object to hold information for the object. The state of an object is defined by it’s attributes. Modifying the attributes leads to state transition of the object.

Car carOne = new Car();         // created new object carOne
// Setting the state of the object.
carOne.model = "Carrera GT";
carOne.color = "Guards Red";

In the above example, attributes of carOne are model and color. They hold information about the object like what is the model of the car and color of the car.

Procedure

A procedure, is a series of steps that can compute on the given data. They contain step-by-step instructions on how the computation should be done. Note the word “how“. That’s because Procedural Paradigm is a subset of Imperative Programming Paradigm.

Huh.. wait what? Weren’t we talking about OOPP? Where did Procedural Paradigm came from?

😅 yeah.. Procedures are part of Procedural Programming which is a sub-paradigm of Imperative Paradigm like Object Oriented Programming. Both Procedural and OOPP are siblings under Imperative Paradigm.

Imperative paradigm and it's children

In Procedural Paradigm, there are no objects and the procedures existence is independent/standalone. They compute on the variables passed to them and return the result. Think of functions in functional programming.

An example

function add(var1, var2) {
    return var1 + var2;
}

add(1, 2)    // returns 3

In the above example, the procedure add is independent. It computes on the input variables to return the result.

But in OOPP, the procedures and the variables are bundled inside an object. The procedures in OOPP are,

  1. Tied to the object, hence they are not independent anymore.
  2. Can compute only on the variables of the object.
  3. Only the object can invoke the procedure.
class Counter {
    int total;

    public void increment() {
        this.total++;
    }
}

public class Oopp {
    public static void main(String[] args) {
        Counter counter = new Counter();
        counter.increment();                            // increments count to 1
        counter.increment();                            // increments count to 2
        System.out.println("Count: " + counter.total);  // prints 2
    }
}

In the above example program, I have a class Counter and I have created an object counter for it in the main method. Now note the below points.

  1. The class Counter has a procedure increment and an attribute total.
  2. The procedure increment can only be invoked by the object counter.
  3. The object counter uses the procedure increment to perform computation on it’s own attribute total. This changes the state of the object counter.

So, in OOPP, only an object can operate it’s procedures on itself, changing it’s state or the state of the program.


Concepts of Object Oriented Programming

The below is a list of basic concepts in OOPP. Out of the 6 below, we already covered class and object above. Let’s see the remaining 4.

  • Class
  • Object
  • Inheritance
  • Encapsulation
  • Abstraction
  • Polymorphism

Inheritance

Inheritance in OOPP promotes the reusability of the code in the application. Just like it’s English meaning, inheritance in programming let’s a class to inherit data and procedures from it’s parent classes. The idea is we can create a generic parent class to have attributes or procedures that are common to all it’s child classes. These child classes can inherit such common data and procedures from the parent class rather than having duplicate codes thus promoting reusability.

Let’s consider the living things. I want to create classes for Humans and Dogs.

class Human {
    String name;
    String gender;
    int age;
    String collegeDegree;

    public void walk() {}
    public void run() {}
    public void readBook() {}
}

class Dog {
    String name;
    String gender;
    int age;
    String breed;

    public void walk() {}
    public void run() {}
    public void wagTail() {}
}

In the above classes, most of the data and procedures are duplicated for both the classes. What if we can abstract the common items into a separate class and extend Human and Dog from the new class? This is what inheritance does. Let’s apply inheritance to the above code.

class Animal {
    String name;
    String gender;
    int age;

    public void walk() {}
    public void run() {}
}

class Human extends Animal {
    String collegeDegree;
    public void readBook() {}
}

class Dog extends Animal {
    String breed;
    public void wagTail() {}
}

I have created a new class Animal since dogs and humans are animals. I also moved the common pieces of code into the class Animal and extended Human and Dog from it. The extends keyword denotes that the new class we create is an extension of the existing class. Here, Human extends Animal says that Human is an extension of Animal which is a true statement in the real-world. If I want to create a class for another animal say Cat, I don’t have to duplicate data and procedures. I can simply extend the class Animal to inherit the data and procedures that are common. This is how inheritance promotes reusability.

Encapsulation

Encapsulation is binding the data and the procedures into a single object and add an restriction on what data should be exposed to the outside of the object. We saw how an object bundles the data and procedures inside itself. By applying encapsulation, we can prevent other objects accessing the data of an object directly.

Let’s leverage the our Counter example.

class Counter {
    int total;

    public void increment() {
        this.total++;
    }
}

public class Oopp {
    public static void main(String[] args) {
        Counter counter = new Counter();
        counter.increment();                            // increments count to 1
        counter.increment();                            // increments count to 2
        System.out.println("Count: " + counter.total);  // prints 2
    }
}

In the above code, see how we can access total directly in the main method. The purpose of the Counter class is to track how many times an action was performed. The like button in Facebook is a very good example of a counter. When this is the case, I should not let an external object to modify data in the variable total. But in my program, the variable total is directly accessible which makes it vulnerable and easy to manipulate.

// ...
System.out.println("Count: " + counter.total);  // prints 2
counter.total = 1000;
System.out.println("Count: " + counter.total);  // prints 1000
// ...

As you can see the above code, I added two more lines where I updated the value of total to 1000. Imagine Facebook has this code, no matter how many likes your post gets, at a certain time it will be reset to 1000. We don’t want this to happen do we? Let’s apply encapsulation.

Encapsulation is applied by adding access modifiers. I will be covering types access modifiers in a new post later. Check the updated code below.

class Counter {
    private int total;

    public void increment() {
        this.total++;
    }

    public int getTotal() {
        return total;
    }
}

public class Oopp {
    public static void main(String[] args) {
        Counter counter = new Counter();
        counter.increment();                                // increments count to 1
        counter.increment();                                // increments count to 2
        System.out.println("Count: " + counter.total);      // compile time error
        System.out.println("Count: " + counter.getTotal()); // prints 2
    }
}

Now, we changed the access specifier of the variable total to private which makes makes it inaccessible by outside objects. To access total, the external object should use the publicly exposed method getTotal() and this method is only accessible through the object counter. We just hid the data total of counter from other objects. This is a way of hiding data of an object from other objects. Hence, encapsulation is also called as data hiding.

Abstraction

Abstraction is displaying only the required information and hiding the unnecessary information from the outside world. When applied to an object, it exposes only the required data to other objects and hides the rest.

For example, let’s assume that we are developing an online food ordering app like Swiggy or Zomato. We have to design a class for the customer who orders food. So I create a class Customer as below.

class Customer {
    private String name;
    private String address;
    private int phoneNumber;
    private String favoriteMovie;
    private String collegeDegree;
    private String maritalStatus;

    // rest of the code
}

The class Customer has both relevant and irrelevant fields. A customer is a human and he/she can have fields like favoriteMovie, collegeDegree and maritalStatus. But these fields are unnecessary for a food ordering app. The required data for our app are name, address, and phoneNumber. By applying abstraction, we can move the unnecessary data to a parent class or interface with inheritance and keep the required data in the class Customer.

class Human {
    String collegeDegree;
    private String favoriteMovie;
    private String maritalStatus;

    // rest of the code
}

class Customer extends Human {
    private String name;
    private String address;
    private int phoneNumber;

    // rest of the code
}

In the above updated code, I have applied abstraction and moved the data irrelevant for a food ordering app to a parent class. Now, only the data required for our app are available in the class Customer.

Polymorphism

In general, polymorphism means having more than one form. In programming, we can apply this to make something work in more than one way. For example, let’s consider that we have a classroom with a teacher and students. Here, both the teacher and the students are humans but in this scenario their roles differ. The teacher’s role is to teach and the role of a student is to learn. In general, humans do what they do to live their daily lives. But when being a teacher, the human teaches and likewise when being a student, the human learns. Same human show different behaviors in different situation. This is polymorphism.

Polymorphism can be achieved in two ways.

  1. Overriding
  2. Overloading

Overriding

Overriding is done between a parent class and it’s child classes. By overriding, parent class’s procedure can be given a new behavior in it’s child classes. Let’s take our teacher-student example.

class Human {
    public void performAction() {
        // live daily life
    }
    // rest of the code
}

class Teacher extends Human {
    @Override
    public void performAction() {
        // Teach students
    }
    // rest of the code
}

class Student extends Human {
    @Override
    public void performAction() {
        // Learn from teachers
    }
    // rest of the code
}

In the above code, the method performAction in the class Human defines what a human does which is, in general, humans live their daily life. Down the hierarchy, in it’s child classes Teacher and Student, I have overridden the performAction method to define new behavior. This is because, in the context of a teacher-student scenario, the behaviors of humans are to teach and learn. Now performAction method for the Teacher class defines that it should teach and for the Student class defines that it should learn. Even though they both are humans, their behavior changes as per the context. Thus, applying polymorphism using overriding, we have defined different behaviors.

Overloading

Overloading allows us to define same method multiple times but each with different set of arguments. Let’s take one of our previous examples Counter. We already have a method increment which increments the total by 1. But now let’s assume I have a scenario, where I have to increment total with a given value and not with 1. In this case, I have to add another method to increment total by the given value.

class Counter {
    private int total;

    public void increment() {
        this.total++;
    }

    public void increment(int delta) {
        this.total = this.total + delta;
    }

    public int getTotal() {
        return total;
    }
}

In the above updated code, I added another method increment(int delta) where delta is the number I want to increment total with. Note that both the methods have same name but different set of arguments. The same method increment now has different definitions/forms. Each definition is distinguished by the number of parameters. This process is overloading. To be more precise, this process is functional overloading. We overloaded a method/function to have more than one form. In functional overloading, a method can be overloaded with,

  1. Different number of parameters in the argument list
  2. Different type of parameters in the argument list.

Below is a snippet for functional overloading where the method increment is overloaded with number of arguments and types of arguments.

public void increment() {
    this.total++;
}
public void increment(int delta) {
    this.total = this.total + delta;
}
public void increment(String delta) {
    int intDelta = Integer.parseInt(delta);
    this.total = this.total + intDelta;
}
Operator overloading

The other type of overloading is operator overloading. Similar to functional overloading, operator overloading overloads an operator. Most languages do not support operator overloading. You can find more about operator overloading here.


Advantages and disadvantages of Object Oriented Programming

Advantages

  1. Objects are modeled based on real-world entities which helps to write modular codes. While defining behavior of an object, the programmer doesn’t have to consider the behavior of other objects.
  2. Extensibility is another advantage of OOP. When we need to add more procedures or attributes to an object, the programmer can simply define a new one extending the older one.
  3. The fundamental concepts encourage reusability in OOP. An object can be reused across the project.
  4. Modularity, extensibility and reusability helps in faster and low-cost development.

Disadvantages

  1. Object Oriented Programming requires the programmer to have an object-oriented thinking which might not be easy for few.
  2. It is not suitable for all types of problems. It is more suitable for larger applications.

Object oriented programming and gaming

As a gamer, I wanted to add this part to this post 😁. Most of the video games are object oriented. I’d take Grand Theft Auto series for example. It has various objects like vehicles, weapons, people, mobile phones, etc. Each object have their own properties, procedures and a state. For example, let’s take a car.

An Object Oriented Programming example of game object.
Image credits: https://gta.fandom.com/

A car in the game have it’s own color, top speed limit, type, durability, number of seats, etc. They can have procedures like accelerate, stop, open door, start, close door, explode, etc. We can even paint the car and it’s state will be maintained throughout the game or till it’s destroyed. The concepts of OOP would have applied for this code as well where class for Car would have inherited from a parent class Vehicle, overriding or overloading some of it’s methods.


What’s next?

Read how functions differ from methods in this post.

Check out other paradigms below.


I hope this post was helpful 😊. If you find this post informative, support us by sharing this with fellow programmers in your circle 😀.

For any suggestions, improvements, reviews or if you like us to cover a specific topic, please leave a comment.
Follow us on twitter @thegeeksclan and in Facebook.
#TheGeeksClan #DevCommunity

error

Enjoy this blog? Please spread the word :)