Object Oriented Programming
- it is a style of programming or a programming paradigm
- it combines a group of related variables and functions into a unit
- the unit is referred to as an object
- the variables are referred to as properties
- the functions are referred to as methods
- e.g.: a CAR object
- has properties of "make, model, color"
- and methods of "start(), stop(), move()"
4 pillars of OOP
- Encapsulation
- group related variables and functions that operate on them into objects
- thus reduce complexity and increase reusability
- (summary) hiding the code and data into a single unit
- in other words, it packages complex functionality for ease of programming
- access to individual functions can be restricted
- hide complex functionality in methods
- the true nature of encapsulated data may also be hidden
- benefits of encapsulation
- breaking functionality into small maintainable units
- grouping functions and data together
- supporting testing of software at a granular level
// procedural programming
let baseSalary = 30000;
let overtime = 10;
let rate = 20;
function getWage(baseSalary, overtime, rate) {
return baseSalary + (overtime * rate);
}
getWage(baseSalary, overtime, rate);
// encapsulation - this is better because getWage method does not requires any parameters
// the fewer the number of parameters, the easier it is to use and maintain that function
let employee = {
baseSalary: 30000,
overtime: 10,
rate: 20,
getWage: function() {
return this.baseSalary + (this.overtime * this.rate);
}
};
employee.getWage(); - group related variables and functions that operate on them into objects
- Abstraction
- hide some of the properties and methods from outside
- this will make the interface of those objects simpler
- an object with a few properties and methods is easier to understand than an object with several properties and methods
- this will help reduce the impact of change
- in the future, if changes were to occur in the inner or private methods, none of the changes will leak outside
- because there isn't any code that touches the methods outside of their content object
- in the future, if changes were to occur in the inner or private methods, none of the changes will leak outside
- this will make the interface of those objects simpler
- (summary) hide the details and the complexity and show only the essentials, which reduce complexity & isolate the impact of changes
function Employee(name, age, baseSalary) {
this.name = name;
this.age = age;
this.baseSalary = baseSalary;
let monthlyBonus = 1500;
// abstraction creation
let calculateFinalSalary = function() {
let finalSalary = baseSalary + monthlyBonus;
console.log(finalSalary);
}
this.getEmployeeDetails = function() {
console.log(this.name);
calculateFinalSalary; // abstraction implementation;
}
}
const employee = new Employee("John", 30, 2000);
employee.getEmployeeDetails(); - hide some of the properties and methods from outside
- Inheritance
- it is a mechanism that allows you to eliminate redundant code
- it has a relationship between classes that lets you inherit or extend functionality from 1 class to another
- not all Object Oriented languages are the same
- c++ supports multiple inheritance
- java only supports single inheritance
- each class can extend or inherit functionality from only 1 other class
- classes can implement multiple interfaces
- inheritance relationship
- Parent/Child, Base/Derived, Superclass/Subclass
class Employee { // parent
raiseAmt = 1.04;
constructor(first, last, pay) {
this.first = first;
this.last = last;
this.pay = pay;
}
applyRaise() {
this.pay = parseInt(this.pay * this.raise_amt);
}
}
// Inheritance
class Developer extends Employee { // child
raiseAmt = 1.1;
constructor(first, last, pay, progLang) {
super(first, last, pay) // implement parent class init method
this.progLang = progLang;
}
}
const dev = new Developer("abc", "xyz", 5000, "Javascript")
console.log(dev.pay) // 5000
dev.applyRaise()
console.log(dev.pay) // 5500 - Polymorphism - literally means many forms
- it addresses an object as either super or subtype
- writes methods that accept supertype as arguments
- passes instances of subtypes
- increases code flxibility and reusability
- has 2 types
- Compile time polymorphism (static binding)
- e.g.: method overloading
- having several methods present in a class with the same name but different types/order/number of parameters
- e.g.: method overloading
- Runtime polymorphism (dynamic binding)
- e.g.: method overriding
- means changing the implementation of an inherited method
- Overriding is about same method, same signature but different classes connected through inheritance
- e.g.: method overriding
- Compile time polymorphism (static binding)
class Animal {
constructor(name) {
this.name = name;
}
makeSound() {
console.log("Generic animal sound");
}
}
// polymorphism - override the makeSound method
class Dog extends Animal {
constructor(name) {
super(name);
}
makeSound() {
console.log("Woof!");
}
}
const dog = new Dog("Happy");
dog.makeSound(); // "Woof!"
Value types vs Reference types
- primitives are copied by their value
// example 1
let x = 0;
let y = x;
x = 20; // y = 0, x = 20
// example 2
let number = 10;
function increase(number) {
number++;
}
increase(number);
console.log(number); // number = 10
- objects are copied by their reference
// example 1
let x = { value: 0 };
let y = x;
x.value = 20 // y = { value: 20 }
// example 2
let obj = { value: 10 };
function increase(obj) {
obj.value++;
}
increase(obj);
console.log(obj); // { value: 11 }
Value types
- number, string, boolean, symbol, undefined, null
Reference types
- object, function, array
Factory
// normal code - needs to make multiple of the same objects if have different radius value
const circle = {
radius: 1,
draw: function() {
console.log("draw");
}
}
circle.draw()
// factory function - only need to change the value in the parameter during initialization
function createCircle(radius) {
return {
radius,
draw: function() {
console.log("draw");
}
};
}
const circle = createCircle(1);
circle.draw();
Constructor
// constructor function
function Circle(radius) {
this.radius = radius;
this.draw = function() {
console.log("draw");
}
}
const circle = new Circle(1);
circle.draw();