Object-oriented programming (OOP) organises code into objects that bundle data (attributes) with the functions that work on it (methods), created from blueprints called classes. Its four pillars are encapsulation (hide internal data), abstraction (expose only what is needed), inheritance (reuse behaviour from a parent class) and polymorphism (one interface, many behaviours).
OOP is how most large programs in Java, Python, C# and JavaScript are organised. The ideas are small. What takes practice is deciding what should be a class.
Classes and objects
A class is a blueprint, such as a bank account with an owner and a balance. An object is one real account made from that blueprint. An attribute is a piece of data on the object and a method is something it can do.
class BankAccount:
def __init__(self, owner, balance=0):
self.owner = owner
self._balance = balance # underscore: "please do not touch directly"
def deposit(self, amount):
if amount <= 0:
raise ValueError("Deposit must be positive")
self._balance += amount
def withdraw(self, amount):
if amount > self._balance:
raise ValueError("Insufficient funds")
self._balance -= amount
@property
def balance(self):
return self._balance
class SavingsAccount(BankAccount): # inheritance
def __init__(self, owner, balance=0, rate=0.04):
super().__init__(owner, balance)
self.rate = rate
def add_interest(self):
self.deposit(self._balance * self.rate)
account = SavingsAccount("Asha", 1000)
account.deposit(500)
account.add_interest()
print(account.balance)Output: 1560.0. The account holds 1000, receives a 500 deposit, then earns 4% interest.
The four pillars of OOP
| Pillar | Meaning | In the example |
|---|---|---|
| Encapsulation | Keep data inside the object and control access through methods | _balance is changed only through deposit and withdraw, which check the rules |
| Abstraction | Show what an object does, hide how it does it | Callers use deposit() without knowing how the balance is stored |
| Inheritance | A child class reuses and extends a parent class | SavingsAccount extends BankAccount and adds interest |
| Polymorphism | The same call behaves differently for different types | shape.area() works for any shape |
Polymorphism in Python
class Shape:
def area(self):
raise NotImplementedError
class Circle(Shape):
def __init__(self, r):
self.r = r
def area(self):
return round(3.14159 * self.r ** 2, 2)
class Rectangle(Shape):
def __init__(self, w, h):
self.w, self.h = w, h
def area(self):
return self.w * self.h
for shape in [Circle(2), Rectangle(3, 4)]: # same call, different behaviour
print(type(shape).__name__, shape.area())Output: Circle 12.57 and Rectangle 12
Inheritance in JavaScript
class Animal {
constructor(name) { this.name = name; }
speak() { return `${this.name} makes a sound`; }
}
class Dog extends Animal {
speak() { return `${this.name} barks`; }
}
for (const a of [new Animal("Generic"), new Dog("Bruno")]) console.log(a.speak());Output: Generic makes a sound and Bruno barks
All four ideas in Java
abstract class Shape {
abstract double area(); // abstraction: what, not how
}
class Rectangle extends Shape { // inheritance
private final double width, height; // encapsulation: private fields
Rectangle(double width, double height) {
this.width = width;
this.height = height;
}
@Override
double area() { return width * height; } // polymorphism: overriding
}
public class Main {
public static void main(String[] args) {
Shape shape = new Rectangle(3, 4);
System.out.println(shape.area()); // 12.0
}
}OOP vs procedural vs functional
| Style | Organises code around | Good for |
|---|---|---|
| Procedural | Functions that act on shared data | Scripts, small programs |
| Object-oriented | Objects that own their data and behaviour | Large systems with many related entities |
| Functional | Pure functions and immutable data | Data pipelines, concurrency |
Modern code mixes the styles. A useful rule is to prefer composition (an object has another object) over deep inheritance trees (an object is another object).
Frequently asked OOP interview questions
- What is the difference between a class and an object?
- What is the difference between an abstract class and an interface?
- What is the difference between method overloading and overriding?
- What is encapsulation, and how do you achieve it?
- Why is multiple inheritance a problem (the diamond problem)?
- What does a constructor do?
- When would you choose composition over inheritance?
Common mistakes
- Making everything public, so any code can break the object's rules.
- Deep inheritance chains that are hard to follow, where composition would be simpler.
- Classes that do too many jobs. Give each class one clear responsibility.
- Using inheritance only to share code instead of modelling an "is a" relationship.
Build something to make it stick
- A library management system: books, members, loans.
- A parking lot with vehicle types and slot allocation.
- An ATM with accounts and transaction rules.
- A text-adventure game with rooms, items and characters.
Add tests for each class, then put them on GitHub. See the software projects and the Masai guide to introduction to object-oriented programming.
Frequently asked questions
What is OOP in simple words?
A way of writing programs as a set of objects, each holding its own data and the actions it can perform, built from classes.
What are the four pillars of OOP?
Encapsulation, abstraction, inheritance and polymorphism.
What is the difference between a class and an object?
A class is the blueprint. An object is an instance created from that blueprint, with its own values.
Which languages use OOP?
Java, C#, C++, Python, JavaScript, Kotlin, Swift and Ruby all support it.
Is OOP still relevant with functional programming?
Yes. Most production codebases in Java, Python and C# are object-oriented, and many mix in functional ideas.
Learn this with mentors
Programmes for builders and engineers with admissions open: live classes, mentors and project work.


