What is Object Oriented Programming? OOP Explained in Depth

Erin Doherty
Apr 15, 2020
editor-page-cover

Object-oriented programming (OOP) is a fundamental programming paradigm that all developers should have in their toolbox. Today we will break down the basics of what makes a program object-oriented so that you can start to utilize this paradigm in your own projects.

Here’s what will be covered:


What is Object Oriented Programming?

Object Oriented programming (OOP) is a programming paradigm that relies on the concept of classes and objects. It is used to structure a software program into simple, reusable pieces of code blueprints (usually called classes) which are used to create individual instances of objects. Because OOP is a programming paradigm, there are many object-oriented programming languages including: C++, Java, and Python.

A programmer designs a software program by organizing related pieces of information and behaviors together into a template called a class. Then individual objects are created from the class template. The entire software program runs by having multiple objects interact with objects to create the larger program.


Why OOP?

OOP makes code organized, reusable, and easy to maintain. It follows the DRY (Don’t Repeat Yourself) principle used by many programmers to make efficient programs.

OOP also prevents unwanted access to data, or exposing proprietary code through encapsulation and abstraction. Both are discussed further in the “Principles of OOP” section below.

So how do programmers create Object Oriented programs? Well the short answer is by making classes, and creating objects from the classes. Classes form the blueprint for how data & behaviors are structured.

Objects are created for specific instances of a class. As a programmer, you might create a dog class (blueprint) as a standard way to organize all the important information about dogs, and then instantiate an individual dog as an object created from the dog class - like your dog Fluffy.


Building blocks of OOP

For this article, we’ll discuss OOP in JavaScript. Assuming you’ve got a limited familiarity with JavaScript, the code building blocks to build an OOP program we’ll discuss are:

  • classes
  • objects
  • methods
  • attributes
widget

Example OOP Structure

Let’s take a real world problem, and conceptually design an OOP software program. Imagine running a pet sitting camp, with hundreds of pets, and you have to keep track of the names, ages, and days attended for each pet. How would you design simple, reusable software to model the pets?

With hundreds of pets, it would be inefficient to write unique code for each dog. Below we see what that might look like with objects rufus and fluffy.

//Object of one individual dog
var rufus = {
    name: "Rufus",
    birthday: "2/1/2017",
    age: function() {
        return Date.now() - this.birthday;
    },
    attendance: 0
}

//Object of second individual dog
var fluffy = {
    name: "Fluffy",
    birthday: "1/12/2019",
    age: function() {
        return Date.now() - this.birthday;
    },
    attendance: 0
}

Above, there is a lot of duplicated code between both objects - the age() function appears in each object. Since we want the same information for each dog, we can use objects and classes instead.

Grouping related information together to form a class structure makes the code shorter and easier to maintain.

In the pet sitting camp example, here’s how a programmer could think about organizing an OOP:

  1. Group pets into categories Like Dog, Cat
    • Determine the information the software should model for each pet category
  2. Create classes
    • Classes a blueprint of information for each pet
  3. Add Attributes to classes
    • Data fields to store for each pet, like name
  4. Add Behaviors to classes
    • Functionality that each pet needs to do, like bark
  5. Create objects from the class
    • Objects are individual instances of the class template
    • In our case dogs like Rufus & Fluffy

We’ll start with a basic example of OOP representing dogs conceptually, and then discuss the code pieces that make up OOP: classes, methods, and objects using JavaScript.

The diagram below represents how to design an OOP: grouping the related data and behaviors together to form a simple template. In this case, the Dog class is a simplified representation of everything we want to store in the software about dogs. The Dog class is a generic template - containing only the structure about information and behaviors common to all dogs. To create an individual dog, the programmer instantiates an instance of the Dog Class, and passes in information from the individual dog.

Let’s say we wanted to store more information specific to French Bulldogs, we can use the Dog class as a parent class, and add a child class French Bulldog with more behaviors and data. Objects are created, or instantiated, from classes. Rufus is an instance of the dog class. Fluffy & Maisel are instances of the French Bulldog class. Inheritance is the ability to create parent and child classes: the French Bulldog class inherits the Dog class. Inheritance is one of the principles of OOP, more about it in the next section.

widget

Here’s a brief example:

Dog is a parent class with generic methods, a blueprint for creating any type of dog. French Bulldog is a child class of the Dog parent class. The French Bulldog class adds more specific attributes and methods unique to French Bulldogs – like nap. The French Bulldog class also inherits the attributes and methods of the parent class. Next, the programmer creates instances of the French Bulldog class – one named Fluffy and one named Maisel. Fluffy & Maisel can both bark and nap. However, Rufus is an instance of the generic dog parent class, so Rufus can bark but he can’t nap. Nap is a method of the child class, and Rufus is an object created from the parent class Dog.


Classes

In a nutshell, they’re essentially user defined data types. Classes are where the programmer creates a blueprint for the structure of methods and attributes. Individual objects are instantiated, or created from this blueprint. Classes contain fields for attributes, and methods for behaviors. In our dog class example, attributes include name & birthday, while methods include bark() and updateAttendance(). Here’s a code snippet demonstrating how to program a dog class using the JavaScript language.

class Dog {
    constructor(name, birthday) {
        this.name = name;
        this.birthday = birthday;
    }

    //Declare private variables
    _attendance = 0;

    getAge() {
        //Getter
        return this.calcAge();
    }

    calcAge() {
        //calculate age using today's date and birthday
        return Date.now() - this.birthday;
    }
    
    bark() {
        return console.log("Woof!");
    }

    updateAttendance() {
        //add a day to the dog's attendance days at the petsitters
        this._attendance++;
    }
}

Remember the class is a template for modeling a dog, and an object is instantiated from the class representing an individual real world thing - Rufus the dog.


Objects

Of course OOP includes objects! Objects are instances of classes created with specific data, for example in the code snippet below Rufus is an instance of the dog class.

class Dog {
    constructor(name, birthday) {
        this.name = name;
        this.birthday = birthday;
    }

    //Declare private variables
    _attendance = 0;

    getAge() {
        //Getter
        return this.calcAge();
    }

    calcAge() {
        //calculate age using today's date and birthday
        return Date.now() - this.birthday;
    }
    
    bark() {
        return console.log("Woof!");
    }

    updateAttendance() {
        //add a day to the dog's attendance days at the petsitters
        this._attendance++;
    }
}

//instantiate a new object of the Dog class, and individual dog named Rufus
const rufus = new Dog("Rufus", "2/1/2017");

When the new class Dog is called:

  • A new object is created named rufus
  • The constructor runs name & birthday arguments, and assigns values

Programming vocabulary: In JavaScript objects are a type of variable. This may cause confusion, because objects can also be declared without a class template in JavaScript, as shown at the beginning. Objects have states and behaviors. State is defined by data: things like names, birthday, and other information you’d want to store about a dog. Behaviors are methods, the object can undertake.

N/A What is it? Contain Information? Actions? Example
Classes Blueprint Attributes Behaviors defined through methods Dog Template
Objects Instance State, Data Methods Rufus, Fluffy

Attributes

Attributes are the information that is stored. Attributes are defined in the Class template. When objects are instantiated individual objects contain data stored in the Attributes field.

The state of an object is defined by the data in the object’s attributes fields. For example, a puppy and a dog might be treated differently at pet camp. The birthday could define the state of an object, and allow the software to handle dogs of different ages differently.


Methods

Methods represent behaviors. Methods perform actions; methods might return information about an object, or update an object’s data. The method’s code is defined in the class definition. When individual objects are instantiated, these objects can call the methods defined in the class. In the code snippet below, the bark method is defined in Dog class, and the bark method is called on the Rufus object.

class Dog {
    //Declare protected (private) fields
    _attendance = 0;

    constructor(name, birthday) {
        this.namee = name;
        this.birthday = birthday;
    }

    getAge() {
        //Getter
        return this.calcAge();
    }

    calcAge() {
        //calculate age using today's date and birthday
        return this.calcAge();
    }

    bark() {
        return console.log("Woof!");
    }

    updateAttendance() {
        //add a day to the dog's attendance days at the petsitters
        this._attendance++;
    }
}

Methods often modify, update or delete data. Methods don’t have to update data though – for example the bark method doesn’t update any data because barking doesn’t modify any of the attributes of the dog class - name or birthday. The updateAttendance() method adds a day the Dog attended the pet sitting camp. The attendance attribute is important to keep track of for billing Owners at the end of the month.

Methods are how programmers promote reusability, and keep functionality encapsulated inside an object. More on encapsulation and data abstraction in the Principles of OOP section. This reusability is a great benefit when debugging – if there’s an error, there’s only one place to find it and fix it instead of many.

Note: the underscore in _attendance denotes that the variable is protected, and shouldn’t be modified directly. The updateAttendance() method is used to change _attendance. For more on private variables in JavaScript, see Implementing Private Variables in JavaScript.


Keep the learning going.

Learn OOP without scrubbing through videos or documentation. Educative’s text-based courses are easy to skim and feature live coding environments - making learning quick and efficient.

Learn OOP in Java, JS, Python, C++, C#



Four principles of OOP

widget

The Four main OOP concepts we’ll talk about are:

  • Inheritance: child classes inherit data and behaviors from parent class
  • Encapsulation: containing information in an object, exposing only selected information
  • Abstraction: only exposing high level public methods for accessing an object
  • Polymorphism: many methods can do the same task

Inheritance

Inheritance allows classes to inherit features of other classes. Put another way, parent classes extend attributes and behaviors to child classes. Inheritance supports reusability – if basic attributes and behaviors are defined in a parent class, child classes can be created extending the functionality of the parent class, and adding additional attributes and behaviors.

Look at an extension of our dog example:

Let’s say that French Bulldogs are a special type of dog that requires more attention than your average dog. We can create a child class FrenchBulldog from the parent class Dog, and then add behaviors. The benefits of inheritance are programs can create a generic parent class, and then create more specific child classes as needed. This simplifies overall programming, because instead of recreating the structure of the Dog class multiple times, child classes can extend the functionality of a parent class.

widget

In the example code snippet, child class French Bulldog inherits the method bark from the parent class Dog, and the child class adds an additional method - nap. Notice that the FrenchBulldog class does not have a copy of the bark method, it inherits the bark method defined in the parent Dog class.

//Parent class Dog
class Dog{
    //Declare protected (private) fields
    _attendance = 0;

    constructor(namee, birthday) {
        this.name = name;
        this.birthday = birthday;
    }

    getAge() {
        //Getter
        return this.calcAge();
    }

    calcAge() {
        //calculate age using today's date and birthday
        return this.calcAge();
    }

    bark() {
        return console.log("Woof!");
    }

    updateAttendance() {
        //add a day to the dog's attendance days at the petsitters
        this._attendance++;
    }
}

//Child class French Bulldog, inherits from parent
class FrenchBulldog extends Dog {
    constructor(name, birthday) {
        super(name);
        super(birthday);
    }

    nap() {
        //additional method for FrenchBulldog child class
        return console.log("Snore")
    }
}

When the code calls fluffy.bark() method, the bark method walks up the chain of child => parent classes, to find where the bark method is defined.

//Parent class Dog
class Dog{
    //Declare protected (private) fields
    _attendance = 0;

    constructor(namee, birthday) {
        this.name = name;
        this.birthday = birthday;
    }

    getAge() {
        //Getter
        return this.calcAge();
    }

    calcAge() {
        //calculate age using today's date and birthday
        return this.calcAge();
    }

    bark() {
        return console.log("Woof!");
    }

    updateAttendance() {
        //add a day to the dog's attendance days at the petsitters
        this._attendance++;
    }
}

//Child class French Bulldog, inherits from parent
class FrenchBulldog extends Dog {
    constructor(name, birthday) {
        super(name);
        super(birthday);
    }

    nap() {
        //additional method for FrenchBulldog child class
        return console.log("Snore")
    }
}

//instantiate a new FrenchBulldog object
const fluffy = new FrenchBulldog("Fluffy", "1/12/2019");
fluffy.bark();

Note: Parent class is also known as super class, or base class. Child class can also be called derived class, or extended class.

In JavaScript, inheritance is also known as prototyping. A prototype object acts as a template for another object to inherit properties and behaviors from. There can be multiple prototype object templates, creating a prototype chain. Same concept as the parent/child inheritance. Inheritance is from parent to child - in our example all three dogs can bark, but only Maisel and Fluffy can nap. The nap() method is defined in the child French Bulldog class, so the two objects - Maisel and Fluffy - instantiated from the French Bulldog class have access to the nap method. Rufus is an object instantiated from the parent class, so Rufus doesn’t have access to the bark() method.

Object Instantiated from Class Parent Class Methods
Rufus Dog N/A Bark
Maisel French Bulldog Dog Bark, nap
Fluffy French Bulldog Dog Bark, nap

Encapsulation

Encapsulation is containing all important information inside an object, and only exposing selected information to the outside world. Attributes and behaviors are defined by code inside the class template. Then, when an object is instantiated from the class, the data and methods are encapsulated in that object. Encapsulation hides the internal software code implementation inside a class, and hides internal data of inside objects. Encapsulation requires defining some fields as private and some as public.

  • Private/ Internal interface – methods and properties, accessible from other methods of the same class.
  • Public / External Interface – methods and properties, accessible also from outside the class.

Let’s use a car as a metaphor for encapsulation. The information the car shares with the outside world - through blinkers to indicate turns, are public interfaces. In contrast, the engine is hidden under the hood - it’s a private, internal interface. When you’re driving a car down the road, other drivers require information to make decisions, like whether you’re turning left or right. However, exposing internal, private data like the engine temperature, would just confuse other drivers.

widget

Encapsulation adds security. Attributes and methods can be set to private, so they can’t be accessed outside the class. To get information about data in an object, public methods & properties are used to access or update data. This adds a layer of security, where the developer chooses what data can be seen on an object by exposing that data through public methods in the class definition.

Within classes, most programming languages have public, protected, and private sections. Public is the limited selection of methods available to the outside world, or other classes within the program. Protected is only accessible to child classes. Private code can only be accessed from within that class. To go back to our dog/owner example, encapsulation is ideal so owners can’t access private information about other people’s dogs.

Note: JavaScript has private and protected properties and methods. Protected Fields are prefixed with a _ ; private fields are prefixed with a #. Protected fields are inherited, private ones aren’t. See this Private and protected properties and methods article for a good explanation.

//Parent class Dog
class Dog{
    //Declare protected (private) fields
    _attendance = 0;

    constructor(namee, birthday) {
        this.name = name;
        this.birthday = birthday;
    }

    getAge() {
        //Getter
        return this.calcAge();
    }

    calcAge() {
        //calculate age using today's date and birthday
        return this.calcAge();
    }

    bark() {
        return console.log("Woof!");
    }

    updateAttendance() {
        //add a day to the dog's attendance days at the petsitters
        this._attendance++;
    }
}

//instantiate a new instance of Dog class, an individual dog named Rufus
const rufus = new Dog("Rufus", "2/1/2017");
//use getter method to calculate Rufus' age
rufus.getAge();

Consider the getAge() method in our example code, the calculation details are hidden inside the Dog class. The rufus object uses the getAge() method to calculate Rufus’s age.

Encapsulating & updating data: Since methods can also update an object’s data, the developer controls what values can be changed through public methods. This allows developers to hide important information that should not be changed - like a social security number - from both phishing and the more likely scenario of other developers mistakenly changing important data.

Encapsulation adds security to code and makes it easier to collaborate with external developers. When you’re programming to share information with an external company, you wouldn’t want to expose the classes’ templates or private data because your company owns that intellectual property. Instead, developers create public methods that allow other developers to call methods on an object. Ideally, these public methods come with documentation for the external developers.

Benefits of encapsulation:

  • Adds security
    • Only public methods and attributes are accessible from the outside
  • Protects developers from common mistakes
    • Only public fields & methods accessible, so developers don’t accidentally change something dangerous
  • Protects IP
    • Code is hidden in a class, only public methods are accessible by the outside developers
  • Supportable
    • most code undergoes updates and improvements
  • Developer can change internal code in the class without alerting users
    • As long as the public attributes & methods stay the same, internal code can be updated without changing existing objects
  • Hides complexity
    • No one can see what’s behind the object’s curtain!

Abstraction

Abstraction means that the user interacts with only selected attributes and methods of an object. Abstraction uses simplified, high level tools, to access a complex object.

  • Using simple things to represent complexity
    • Objects, classes represent more complex underlying code
  • Hide complex details from user

Abstraction is using simple classes to represent complexity. Abstraction is an extension of encapsulation. For example, you don’t have to know all the details of how the engine works to drive a car. A driver only uses a small selection of tools: like gas pedal, brake, steering wheel, blinker. The engineering is hidden from the driver. To make a car work, a lot of pieces have to work under the hood, but exposing that information to the driver would be a dangerous distraction.

widget

Abstraction also serves an important security role – by only displaying selected pieces of data, and only allowing data to be accessed through classes and modified through methods, the developer protects the data from exposure. To continue with the car example, you wouldn’t want an open gas tank while driving a car.

Benefits of abstraction:

  • Simple, high level user interfaces
  • Complex code is hidden
  • Security
    • Only chosen parts of object are accessible
  • Easier software maintenance
    • Code updates rarely change abstraction

Polymorphism

Polymorphism is designing objects to share behaviors. Using inheritance, objects can override shared parent behaviors, with specific child behaviors. Polymorphism allows the same method to execute different behaviors in two ways: method overriding and method overloading.


Method Overriding

Runtime polymorphism uses method overriding. In method overriding, a child class can provide a different implementation than its parent class. In our dog example, we may want to give French Bulldogs a specific type of bark different than the generic dog class. Method overriding could create a bark() method in the child class that overrides the bark() method in the parent dog class.

//Parent class Dog
class Dog{
    //Declare protected (private) fields
    _attendance = 0;

    constructor(namee, birthday) {
        this.name = name;
        this.birthday = birthday;
    }

    getAge() {
        //Getter
        return this.calcAge();
    }

    calcAge() {
        //calculate age using today's date and birthday
        return this.calcAge();
    }

    bark() {
        return console.log("Woof!");
    }

    updateAttendance() {
        //add a day to the dog's attendance days at the petsitters
        this._attendance++;
    }
}

//Child class French Bulldog, inherits from parent
class FrenchBulldog extends Dog {
    constructor(name, birthday)
        super(name);
        super(birthday);
    }

    nap() {
        //additional method for FrenchBulldog child class
        return console.log("Snore")
    }

    bark() {
        return console.log("French bark!");
    }


//instantiate a new French Bulldog object
const fluffy = new FrenchBulldog("Fluffy", "1/12/2019");
fluffy.bark(); //returns "French bark!"
widget

Method Overloading

Compile Time polymorphism uses method overloading. Methods or functions may have the same name, but a different number of parameters passed into the method call. Different results may occur depending on the number of parameters passed in.

//Parent class Dog
class Dog{
    //Declare protected (private) fields
    _attendance = 0;

    constructor(namee, birthday) {
        this.name = name;
        this.birthday = birthday;
    }

    getAge() {
        //Getter
        return this.calcAge();
    }

    calcAge() {
        //calculate age using today's date and birthday
        return this.calcAge();
    }

    bark() {
        return console.log("Woof!");
    }

    updateAttendance() {
        //add a day to the dog's attendance days at the petsitters
        this._attendance++;
    }

    updateAttendance(x) {
        //adds multiple to the dog's attendance days at the petsitters
        this._attendance = this._attendance + x;
    }
}

//instantiate a new instance of Dog class, an individual dog named Rufus
const rufus = new Dog("Rufus", "2/1/2017");
rufus.updateAttendance(); //attendance = 1
rufus.updateAttendance(4); // attendance = 5

In this code example, if no parameters are passed into the updateAttendance() method - one day is added to the count. If a parameter is passed in - updateAttendance(4), then 4 is passed into the x parameter in updateAttendance(x), and 4 days are added to the count.

The benefits of Polymorphism are:

  • Objects of different types can be passed through the same interface
  • Method overriding
  • Method overloading

Notes to remember

  • OOP: Everything is an object

  • Code building blocks

    • Classes are blueprints for objects
    • Objects are instances of classes
    • Attributes are data fields
    • Methods are behaviors
  • Object oriented programming concepts

    • Inheritance: child classes inherit attributes and code from parent classes
    • Encapsulation: only exposing selected information to the outside world
    • Abstraction: creating a simple model that represents the complex data & behaviors
    • Polymorphism: when multiple objects can implement the same functionality

Benefits of OOP

  • OOP models complex things as reproducible, simple structures
  • OOP code is reusable
  • OOP prevents duplicating code
  • OOP makes fixing bugs easier. Fixing an error contained in a well-structured class is easier than finding the error in multiple places in code.
  • OOP protects information through encapsulation Object’s data can only be accessed through public properties and methods
  • OOP uses abstraction to make complexity digestible
  • OOP is easy to work with in a team of developers – classes can be assigned out to different developers, allowing multiple people to code a project at the same time.

Conclusion

Object Oriented programming requires thinking about the structure of the program and planning at the beginning of coding. Looking at how to break up the requirements into simple, reusable classes that can be used to blueprint instances of objects. Overall, implementing OOP allows for better data structures and reusability, saving time in the long run.

If you’d like to take a deep dive into OOP, Educative has courses for OOP in:

These courses are text-based with in-browser coding environments so you can learn even faster and more efficiently. No set-up required, just get in and start coding.

Happy learning!

WRITTEN BY

Erin Doherty