01
Object
In OOP, an Object is a real-world entity that has properties (attributes) and behaviors (methods). It is an instance of a Class, which acts as a blueprint.
Real-Life Example:
Imagine you are building an Inventory Management System for a warehouse. One of the objects in this system could be a Product.
public class Product {
private String productName;
private int productID;
private double price;
private int stockQuantity;
public Product(String productName, int productID, double price, int stockQuantity) {
this.productName = productName;
this.productID = productID;
this.price = price;
this.stockQuantity = stockQuantity;
}
public void displayProductDetails() {
System.out.println("Product Name: " + productName);
System.out.println("Product ID: " + productID);
System.out.println("Price: " + price);
System.out.println("Stock Quantity: " + stockQuantity);
}
// Getters and Setters
public String getProductName() { return productName; }
public void setProductName(String productName) { this.productName = productName; }
// Other Getters and Setters
}
- Product is an object that has properties like
productName
,productID
,price
, andstockQuantity
. - The behavior of the Product object is shown in the
displayProductDetails()
method, which prints the details of the product.
Real-Life Usage:
In an Inventory Management System, each Product object could represent an actual product in the warehouse, with its own attributes (name, price, etc.) and behaviors (e.g., update stock, print product details).

02
Class
A Class in OOP is like a blueprint for creating objects. It defines properties (attributes) and behaviors (methods) that the objects created from the class will have. In simple terms, a class is a template for creating objects.
Real-Life Example: Product Class
Let’s continue with our Inventory Management System. We already have the Product object, but now we’ll define the Product Class, which acts as the blueprint for creating multiple product objects.
public class Product {
// Properties (Attributes) of the Product class
private String productName;
private int productID;
private double price;
private int stockQuantity;
// Constructor to initialize a Product object
public Product(String productName, int productID, double price, int stockQuantity) {
this.productName = productName;
this.productID = productID;
this.price = price;
this.stockQuantity = stockQuantity;
}
// Methods (Behaviors) of the Product class
public void displayProductDetails() {
System.out.println("Product Name: " + productName);
System.out.println("Product ID: " + productID);
System.out.println("Price: " + price);
System.out.println("Stock Quantity: " + stockQuantity);
}
// Getters and Setters
public String getProductName() { return productName; }
public void setProductName(String productName) { this.productName = productName; }
// Other Getters and Setters for other properties
}
Breakdown:
- Class Definition: The
Product
class defines the blueprint for product objects. It has attributes likeproductName
,productID
,price
, andstockQuantity
. - Constructor: The constructor (
Product(String productName, int productID, double price, int stockQuantity)
) is used to create a new product object with specific values. - Methods: The
displayProductDetails()
method is a behaviour of the product that prints the details of the product to the console.
Real-Life Usage:
In a warehouse system, you can have many products, and each product is created from the Product class. The Product
class provides a standardised structure for storing the data, and each product object created from it can have its unique attributes like name, price, and stock quantity.

03
Inheritance
Inheritance allows one class (called the child class or subclass) to inherit properties and behaviors (methods) from another class (called the parent class or superclass). This concept promotes code reuse and establishes a hierarchical relationship between classes.
Real-Life Example: Product and Electronics
In an inventory management system, we might have a generic Product class, and then a more specialized class, such as Electronics, that inherits from the Product class. This way, we can reuse the common attributes and methods from the Product class while adding specific attributes or behaviors for the Electronics class.
// Parent class (Product)
public class Product {
private String productName;
private int productID;
private double price;
private int stockQuantity;
public Product(String productName, int productID, double price, int stockQuantity) {
this.productName = productName;
this.productID = productID;
this.price = price;
this.stockQuantity = stockQuantity;
}
public void displayProductDetails() {
System.out.println("Product Name: " + productName);
System.out.println("Product ID: " + productID);
System.out.println("Price: " + price);
System.out.println("Stock Quantity: " + stockQuantity);
}
// Getters and Setters
}
// Child class (Electronics)
public class Electronics extends Product {
private String brand;
private int warrantyPeriod; // in months
public Electronics(String productName, int productID, double price, int stockQuantity, String brand, int warrantyPeriod) {
super(productName, productID, price, stockQuantity); // Call the parent class constructor
this.brand = brand;
this.warrantyPeriod = warrantyPeriod;
}
public void displayElectronicsDetails() {
displayProductDetails(); // Inherited method from Product
System.out.println("Brand: " + brand);
System.out.println("Warranty Period: " + warrantyPeriod + " months");
}
// Getters and Setters for brand and warranty
}
Breakdown:
- Product Class (Parent Class): This is the general class that defines common properties for all products.
- Electronics Class (Child Class): This class inherits from the Product class, and it adds specific attributes such as brand and warrantyPeriod. It also calls the
displayProductDetails()
method from the Product class and adds its own method to display additional details.
Real-Life Usage:
Product is the base class, and we can have other subclasses like Clothing, Furniture, or Electronics, each inheriting common features from Product but with additional specialized attributes or methods. it can have its unique attributes like name, price, and stock quantity.

04
Polymorphism
Polymorphism allows objects to be treated as instances of their parent class, but they can take on many forms (hence the name “many shapes”). It enables a single method to behave differently based on the object that it is acting upon. There are two types of polymorphism in OOP:
- Compile-time polymorphism (method overloading)
- Runtime polymorphism (method overriding)
Real-Life Example: Payment System
Let’s consider a Payment system where we can have different payment methods like CreditCard and PayPal. Both classes can inherit from a common PaymentMethod class, and each will override the processPayment()
method to behave according to the specific payment type.
// Parent Class (PaymentMethod)
public class PaymentMethod {
public void processPayment() {
System.out.println("Processing payment...");
}
}
// Child Class (CreditCard)
public class CreditCard extends PaymentMethod {
@Override
public void processPayment() {
System.out.println("Processing credit card payment...");
}
}
// Child Class (PayPal)
public class PayPal extends PaymentMethod {
@Override
public void processPayment() {
System.out.println("Processing PayPal payment...");
}
}
Breakdown:
- Parent Class (PaymentMethod): The
processPayment()
method in the parent class is generic and works for all payment types. - Child Classes (CreditCard and PayPal): These child classes override the
processPayment()
method to provide specific behavior for each payment method.
Real-Life Usage:
In an online store, when a user selects a payment method (CreditCard, PayPal, etc.), the system will dynamically determine the correct way to process the payment based on the object type (runtime polymorphism). This allows the same method to be used across different payment methods without knowing the exact class type beforehand.

05
Encapsulation
Encapsulation is the concept of bundling the data (attributes) and methods that operate on the data into a single unit, known as a class. It also involves restricting direct access to some of the object’s components, which helps in data hiding. The goal of encapsulation is to protect the object’s internal state by only allowing access through well-defined methods (getters and setters).
Real-Life Example: Bank Account
Let’s consider a BankAccount class where we want to encapsulate the account balance. We don’t want external users to directly change the balance but instead use methods like deposit()
and withdraw()
to modify the balance. We can achieve this by making the balance private and providing controlled access through public methods.
// BankAccount class demonstrating Encapsulation
public class BankAccount {
// Private attribute: The balance is hidden from external access
private double balance;
// Constructor to initialize the balance
public BankAccount(double initialBalance) {
this.balance = initialBalance;
}
// Public method to deposit money
public void deposit(double amount) {
if (amount > 0) {
balance += amount;
System.out.println("Deposited: " + amount);
} else {
System.out.println("Invalid deposit amount.");
}
}
// Public method to withdraw money
public void withdraw(double amount) {
if (amount > 0 && amount <= balance) {
balance -= amount;
System.out.println("Withdrew: " + amount);
} else {
System.out.println("Invalid withdrawal amount.");
}
}
// Getter method to retrieve the balance
public double getBalance() {
return balance;
}
}
Breakdown:
- Private Attribute: The
balance
is markedprivate
, so it can’t be accessed directly from outside the class. - Public Methods:
deposit()
,withdraw()
, andgetBalance()
are public methods that control how thebalance
can be changed or accessed. These methods ensure that no invalid operations occur on thebalance
(e.g., negative deposits or withdrawals that exceed the available balance). - Encapsulation: The internal state of the object (balance) is protected, and only authorized actions (depositing and withdrawing) can modify it.
Real-Life Usage:
In a banking system, this ensures that customers can’t directly manipulate their account balance, but instead, they interact with the account through controlled methods.

06
Abstraction
Abstraction is the concept of hiding the complex implementation details of a system and exposing only the necessary parts to the user. It allows a programmer to focus on high-level functionality without needing to understand the complex code behind it. In OOP, abstraction is often achieved through abstract classes and interfaces.
Real-Life Example: Vehicle System
Let’s consider a Vehicle system where we have various types of vehicles like Car and Bike. The common functionality like start() and stop() can be abstracted out in a Vehicle abstract class, while each specific vehicle class can implement these functionalities in its own way.
// Abstract Class (Vehicle)
public abstract class Vehicle {
// Abstract methods
public abstract void start();
public abstract void stop();
}
// Concrete Class (Car)
public class Car extends Vehicle {
@Override
public void start() {
System.out.println("Starting the car...");
}
@Override
public void stop() {
System.out.println("Stopping the car...");
}
}
// Concrete Class (Bike)
public class Bike extends Vehicle {
@Override
public void start() {
System.out.println("Starting the bike...");
}
@Override
public void stop() {
System.out.println("Stopping the bike...");
}
}
Breakdown:
- Abstract Class (Vehicle): The
Vehicle
class is abstract, meaning it can’t be instantiated directly. It defines thestart()
andstop()
methods, but doesn’t provide implementations for them. - Concrete Classes (Car and Bike): Both the Car and Bike classes extend the Vehicle class and provide their own implementations for the
start()
andstop()
methods.
Real-Life Usage:
In a Vehicle Management System, the user can interact with a Vehicle
object and call start()
and stop()
methods, without needing to know whether it’s a car or a bike. The implementation details are abstracted away, and only the relevant interface is provided.

Design Patterns in OOP
Design patterns are reusable solutions to common software design problems. They offer time-tested strategies for solving issues in software architecture. We will cover some key design patterns in OOP and explain them with real-life examples.
01
Singleton Pattern
The Singleton Pattern ensures that a class has only one instance and provides a global point of access to that instance.
Real-Life Example: Database Connection
In a large system, you might want to ensure that there is only one instance of the database connection. The DatabaseConnection class will use the Singleton pattern to ensure only one connection instance is created, no matter how many times it’s accessed.
public class DatabaseConnection {
private static DatabaseConnection instance;
// Private constructor to prevent instantiation
private DatabaseConnection() {
// Connect to the database
}
// Public method to get the instance
public static DatabaseConnection getInstance() {
if (instance == null) {
instance = new DatabaseConnection();
}
return instance;
}
// Method to execute queries
public void executeQuery(String query) {
// Execute the query
}
}
Breakdown:
- The DatabaseConnection class has a private static variable
instance
to hold the single instance. - The constructor is private to prevent direct instantiation of the class.
- The
getInstance()
method ensures that only one instance is created.
Real-Life Usage:
In a web application, you only want one database connection to reduce overhead and ensure consistency across multiple requests.

02
Factory Pattern
The Factory Pattern provides a way to create objects without specifying the exact class of object that will be created. Instead, the factory method delegates the responsibility of instantiating the object to subclasses or to a specialised factory class.
Real-Life Example: Notification System
Let’s imagine you are building a Notification System where you need to send different types of notifications like Email, SMS, and Push Notification. Instead of directly instantiating the notification classes, the NotificationFactory class can decide which notification to create based on user preferences.
// Product Interface
public interface Notification {
void sendNotification();
}
// Concrete Product (EmailNotification)
public class EmailNotification implements Notification {
@Override
public void sendNotification() {
System.out.println("Sending email notification...");
}
}
// Concrete Product (SMSNotification)
public class SMSNotification implements Notification {
@Override
public void sendNotification() {
System.out.println("Sending SMS notification...");
}
}
// Concrete Product (PushNotification)
public class PushNotification implements Notification {
@Override
public void sendNotification() {
System.out.println("Sending push notification...");
}
}
// Factory Class
public class NotificationFactory {
public static Notification createNotification(String type) {
if (type.equals("Email")) {
return new EmailNotification();
} else if (type.equals("SMS")) {
return new SMSNotification();
} else if (type.equals("Push")) {
return new PushNotification();
}
return null;
}
}
Breakdown:
- Notification Interface: This defines a method
sendNotification()
that must be implemented by all types of notifications. - Concrete Products (EmailNotification, SMSNotification, PushNotification): These are specific types of notifications that implement the
Notification
interface. - Factory Class (NotificationFactory): The
createNotification()
method in the factory decides which notification object to create based on the type provided.
Real-Life Usage:
In a Notification System, the factory pattern allows you to create the appropriate notification object without knowing which class will be used. This decouples the code that uses notifications from the specific types of notifications.

03
Observer Pattern
The Observer Pattern defines a one-to-many dependency between objects, where a change in one object (the subject) automatically updates all dependent objects (the observers). It is particularly useful in scenarios where multiple components need to be notified of changes in a single entity, such as in event-driven systems or UI updates.
Real-Life Example: Weather Monitoring System
Let’s consider a Weather Monitoring System, where multiple devices like Smartphones, Laptops, and Tablets need to be updated when the weather data changes (temperature, humidity, etc.). The WeatherStation acts as the subject, and the devices (smartphones, tablets, etc.) are observers that get updated whenever the weather data changes.
import java.util.ArrayList;
import java.util.List;
// Subject Interface
public interface WeatherStation {
void addObserver(Device device);
void removeObserver(Device device);
void notifyObservers();
}
// Concrete Subject
public class ConcreteWeatherStation implements WeatherStation {
private List<Device> devices = new ArrayList<>();
private String weatherData;
@Override
public void addObserver(Device device) {
devices.add(device);
}
@Override
public void removeObserver(Device device) {
devices.remove(device);
}
@Override
public void notifyObservers() {
for (Device device : devices) {
device.update(weatherData);
}
}
// Method to change weather data
public void setWeatherData(String weatherData) {
this.weatherData = weatherData;
notifyObservers(); // Notify all observers about the update
}
}
// Observer Interface
public interface Device {
void update(String weatherData);
}
// Concrete Observer (Smartphone)
public class Smartphone implements Device {
@Override
public void update(String weatherData) {
System.out.println("Smartphone received weather update: " + weatherData);
}
}
// Concrete Observer (Tablet)
public class Tablet implements Device {
@Override
public void update(String weatherData) {
System.out.println("Tablet received weather update: " + weatherData);
}
}
Breakdown:
- Subject (WeatherStation): The
WeatherStation
is the subject, maintaining a list of observers (devices) and notifying them of changes. - Observer (Device): The
Device
interface is implemented by concrete observers like Smartphone and Tablet, which receive updates when the weather changes. - Concrete Subject (ConcreteWeatherStation): This class handles the actual weather data and notifies the observers when the data changes.
Real-Life Usage:
In a weather monitoring system, whenever the weather changes (e.g., a temperature update), the system notifies all registered devices (smartphones, tablets, etc.) in real-time.

04
Strategy Pattern
The Strategy Pattern is a behavioral design pattern that defines a family of algorithms, encapsulates each one, and makes them interchangeable. This allows a class to change its behavior at runtime, based on the strategy it selects.
Real-Life Example: Tax Calculation System
In a Tax Calculation System, different countries or regions have different tax calculation strategies. Instead of hardcoding tax calculation logic, the TaxCalculator class can use the Strategy Pattern to dynamically choose the appropriate strategy based on the user’s region.
// Strategy Interface
public interface TaxStrategy {
double calculateTax(double income);
}
// Concrete Strategy (US Tax)
public class USTaxStrategy implements TaxStrategy {
@Override
public double calculateTax(double income) {
return income * 0.25; // Example: 25% tax
}
}
// Concrete Strategy (EU Tax)
public class EUTaxStrategy implements TaxStrategy {
@Override
public double calculateTax(double income) {
return income * 0.20; // Example: 20% tax
}
}
// Context Class
public class TaxCalculator {
private TaxStrategy taxStrategy;
// Constructor to set the strategy
public TaxCalculator(TaxStrategy taxStrategy) {
this.taxStrategy = taxStrategy;
}
// Method to calculate tax based on the selected strategy
public double calculate(double income) {
return taxStrategy.calculateTax(income);
}
}
Breakdown:
- Strategy Interface: The
TaxStrategy
interface defines the methodcalculateTax()
, which will be implemented by concrete strategies. - Concrete Strategies (USTaxStrategy, EUTaxStrategy): These classes implement the
TaxStrategy
interface, each providing a different tax calculation. - Context (TaxCalculator): This class uses a specific strategy for tax calculation. The strategy is passed to the constructor, and the
calculate()
method uses the chosen strategy.
Real-Life Usage:
In a multi-country e-commerce platform, the TaxCalculator class can use different tax strategies for US, EU, and other countries based on the user’s region.m notifies all registered devices (smartphones, tablets, etc.) in real-time.

05
Decorator Pattern
The Decorator Pattern allows you to add new functionality to an object without altering its structure. It provides a flexible alternative to subclassing for extending functionality.
Real-Life Example: Coffee Shop Order
In a Coffee Shop, you can order a basic coffee and then decorate it with extras like milk, sugar, or whipped cream. Instead of creating new classes for each combination, you can use the decorator pattern to add these extras dynamically.
public interface Coffee {
double cost();
}
public class SimpleCoffee implements Coffee {
@Override
public double cost() {
return 5.0; // Base price of a simple coffee
}
}
public class MilkDecorator implements Coffee {
private Coffee coffee;
public MilkDecorator(Coffee coffee) {
this.coffee = coffee;
}
@Override
public double cost() {
return coffee.cost() + 1.0; // Add cost of milk
}
}
public class SugarDecorator implements Coffee {
private Coffee coffee;
public SugarDecorator(Coffee coffee) {
this.coffee = coffee;
}
@Override
public double cost() {
return coffee.cost() + 0.5; // Add cost of sugar
}
}
Breakdown:
Decorators (MilkDecorator, SugarDecorator): These classes add additional functionality to the base coffee object by “decorating” it with new features like milk or sugar.
Coffee Interface: This defines a cost()
method.
SimpleCoffee: The basic coffee class that implements the Coffee
interface.

06
Command Pattern
The Command Pattern turns requests or simple operations into objects. This allows for parameterizing clients with different requests, queuing requests, and logging the requests.
Real-Life Example: Remote Control for Devices
In a Remote Control system, different commands like Power On, Volume Up, and Change Channel can be turned into command objects that the remote control can execute.
public interface Command {
void execute();
}
public class LightOnCommand implements Command {
private Light light;
public LightOnCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.turnOn();
}
}
public class Light {
public void turnOn() {
System.out.println("The light is on");
}
public void turnOff() {
System.out.println("The light is off");
}
}
Breakdown:
Receiver (Light): The object that performs the action (turning on/off the light).
Command Interface: Defines the execute()
method for all commands.
Concrete Command (LightOnCommand): A concrete command that turns the light on when executed.
