Object-Oriented Programming

Object-Oriented Programming (OOP) is a computer programming model that organizes software design. It relies on the concept of classes and objects.
A class is an abstract blueprint used to create more specific, concrete objects. The class contains methods (functions) and properties (variables) we can access these methods and properties by creating an object from class.

Object-oriented programming benefits

  • Faster and easier to execute.
  • Provides a clear structure for the programs.
  • Helps to keep your code dry “do not repeat yourself” makes the code easier to maintain, modify and debug.
  • Makes it possible to create a full reusable application with less code and shorter development time.
  • Modularity Objects are self-contained which making development and troubleshooting easier.
  • Reusability Code can be used through inheritance a team does not have to write the same code multiple times.
  • Scalability Developers can implement system functionalities independently.
  • Security Using encapsulation and abstraction, complex code is hidden and protected.
  • Flexibility by using polymorphism.

Structure of object oriented programming

DRY “do not repeat yourself” principle is about reducing the repetition of code you should extract out the comman code in application and place it into a single place and reuse them instead of repeating it.

  • Classes are user-defined data types that act as the blueprint for individual objects, attributes and methods.
  • Objects are instances of a class which allow us to access and use properties and methods defined in the class.
  • Methods are functions that are defined inside a class.
  • Attributes are the class variables which used for storing data.

Now let’s take a real world problem and design software oop solution for this problem Suppose we will create a school program to record students.

let firstStudent = {
    name:"Ahmed Mahmoud",
    dateOfBirth:"08-15-2000",
    age(){
        let currentDate = new Date().getTime();
        let dob = new Date(this.dateOfBirth).getTime();
        let years = Math.floor((currentDate-dob)/(365 * 24 * 60 * 60 * 1000));
        return years;
    }
}
let secondStudent ={
    name:"Mohamed Ali",
    dateOfBirth:"09/11/2000",
    age(){
        let currentDate = new Date().getTime();
        let dob = new Date(this.dateOfBirth).getTime();
        let years = Math.floor((currentDate-dob)/(365 * 24 * 60 * 60 * 1000));
        return years;
    }
}

In case we have 1000 students could you imagine the number of code duplications especially with age() function it’s a very bad design. Code duplication wastes memory and processor. Now let’s use the power of object-oriented programming by creating a Student class and create objects from this class.

class Student{
    constructor(name,dateOfBirth){
        this.name = name;//attributes or property
        this.dateOfBirth  = dateOfBirth;
        this.age=this.getAge()
    }
    //Method a function defined within class
    getAge(){
        let currentDate = new Date().getTime();
        let dob = new Date(this.dateOfBirth).getTime();
        let years = Math.floor((currentDate-dob)/(365 * 24 * 60 * 60 * 1000));
        return years;
    }
}
//object (instance of class) created by using new keyword 
const firstStd = new Student("Ahmed Mahmoud","08-15-2000");
const secondStd = new Student("Mohamed Ali","09-11-2000");
console.log(firstStd)//Student { name: 'Ahmed Mahmoud', dateOfBirth: '08-15-2000', age: 21 }
console.log(secondStd)//Student { name: 'Mohamed Ali', dateOfBirth: '09-11-2000', age: 20 }

Class Visibility

visibility determines how properties and methods are accessible.

  • public can be accessed anywhere.
  • protected can be accessed in class and sub-class.
  • private can be accessed inside the class only not-inherited can not be used inside sub-class.

Note: Protected properties are usually prefixed with an underscore _ . That is not enforced on the language level, but there’s a well-known convention between programmers that such properties and methods should not be accessed from the outside.

In this example, pinCode public property can be accessed inside class and outside class also in the sub-class.

class Student {
  pinCode;
  constructor(name, age) {
    this.name = name;
    this.age = age;
    this.pinCode = Math.floor(Math.random(0, 1) * 10000);
  }
}
const std = new Student("Ahmed", 20);
console.log(std.pinCode);//random value
std.pinCode = 15;//overwrite pinCode value because it's public
console.log(std.pinCode);//15

Here the example of protected property pinCode which accessed inside class and sub-class but can not accessed outside.

class Student {
  _pinCode;
  constructor(name, age) {
    this.name = name;
    this.age = age;
    this._pinCode = Math.floor(Math.random(0, 1) * 10000);
  }
  get pinCode() {
    return this._pinCode;
  }
}
const std = new Student("Ahmed", 20);
console.log(std.pinCode);//random value

Here is the example of private property it’s accessed inside the class but can not be outside or in sub-class.
Privates should start with #. They are only accessible from inside the class.

class Student {
  #pinCode;
  constructor(name, age) {
    this.name = name;
    this.age = age;
    this.#pinCode = Math.floor(Math.random(0, 1) * 10000);
  }
  get pinCode() {
    return this.#pinCode;
  }
}
const std = new Student("Ahmed", 20);
console.log(std.pinCode);//random value
console.log(std.#pinCode);//syntax error
std.pinCode = 15;//can not overwitten because it's private
console.log(std.pinCode);//same random value

Static The static keyword defines a static method or property for a class and it’s accessed outside class by className.varName.
Static methods are often utility functions, such as functions to create or clone objects, whereas static properties are useful for caches, fixed-configuration, or any other data you don’t need to be replicated across instances.

class ClassWithStaticMethod {
  static staticProperty = 'someValue';
  static staticMethod() {
    return 'static method has been called.';
  }
}
console.log(ClassWithStaticMethod.staticProperty);
// output: "someValue"
console.log(ClassWithStaticMethod.staticMethod());
// output: "static method has been called."

Main principles of OOP

Encapsulation

Encapsulation is hide the sensitive data from users.
Why encapsulation?

  • Security (access control)
  • Hide implementation and expose behavior.
  • Loose coupling modifies the implementation at any time.
class Employee{
    #id;
    #name;
    #phone;
    #age;

    setEmployeeDetails({id,name,phone,age}){
        this.#id=id;
        this.#name=name;
        this.#phone=phone;
        this.#age=age;
    }
    getEmpId(){
        return this.#id;
    }
    getEmpName(){
        return this.#name;
    }
    getEmpPhone(){
        return this.#phone;
    }
    getEmpAge(){
        return this.#age;
    }
}
const emp = new Employee();
emp.setEmployeeDetails({id:"nb3422190xzs908",name:"Ahmed Mahmoud",age:26,phone:"+x-xxxx-xxxx"});
console.log(emp.getEmpName());

Inheritance

Inheritance are a concept of programming in which there is a parent class and another child one inherits methods & properties defined and implemented in parent class using extends keyword.
This an example about Inheritance

class Animal {
  constructor(legs) {
    this.legs = legs;
  }
  walk() {
    console.log("walking on " + this.legs + " legs");
  }
}
class Bird extends Animal {
  constructor(legs) {
    super(legs);
  }
  fly() {
    console.log("flying");
  }
}
let bird = new Bird(2);
bird.walk();
bird.fly();

Abstraction

Abstraction “shows” only essential attributes and “hides” unnecessary information. The main purpose of abstraction is to hide unnecessary details from the users which reducing programming complexity and efforts. also Encapsulation for protecting data. (Hide details and show only the essentials)

class Employee {
  #bouns = 1000;
  constructor(name, age, basicSalary) {
    this.name = name;
    this.age = age;
    this.basicSalary = basicSalary;
  }
  #getFullSalary() {
    return this.basicSalary + this.#bouns;
  }
  getEmpDetails() {
    console.log(
      `Name:${this.name} | Age:${
        this.age
      } | Full-salary:${this.#getFullSalary()}`
    );
  }
}
const emp = new Employee("Ahmed", 15, 5000);
emp.getEmpDetails();

From this example bouns is a private property not exposed outside the class so no one can change it we protected it because if it’s public anyone can change. and getFullSalary is not exposed also outside class but its result is called inside getEmpDetails so this is the concept of abstraction

Polymorphism

Polymorphism means (many forms) and is the ability of any data to be processed in more than one form. is a core concept of an object-oriented paradigm that provides a way to perform a single action in different forms.

class Animal {
  constructor(name, numOfLegs) {
    this.name = name;
    this.legs = numOfLegs;
  }
  eat() {
    console.log(`${this.name} eats food!!`);
  }
}
class Dog extends Animal {
  eat() {
    console.log(`${this.name} eats bones`);
  }
}
const rocky = new Dog("Rocky", 4);
rocky.eat();

From this example eat() function in Dog class is executed and this is the concept of polymorphism and this is called Overriding is an object-oriented programming concept same function in sub class and parent with the same name but the implementation is different (function behavior). But it should have the same signature (number of arguments, return type, function name)

Note if i want to execute both eat() functions so in the child class in eat() just we call the parent one super.eat()

Overloading is an object-oriented programming concept which function has the same name but different implementation (perform different tasks )based on the arguments passed.

Subscribe to our Newsletter

Subscribe to tech-hour website to get all updates, new articles, new courses and projects. No spam ever. Unsubscribe at any time.