The concept of object-oriented programming
Object-oriented programming (OOP) is a fundamental approach to problem-solving and structuring lines of code. Instead of focusing solely on logic or functions, with this approach, a software solution is organised around objects. This allows developers to model real-world entities and their interactions more intuitively (MDN, 2025). Consider this approach as a toolbox containing several tools such as Objects, Classes, Attributes, Methods, Encapsulation, Abstraction, Inheritance and Polymorphism. These tools serve as building blocks to model real-world entities, their characteristics, behaviours, and more. This helps to design modular, reusable, and scalable software systems.
Imagine a school as a program where teachers are its star objects. A teacher must have some basic attributes like name, gender, speciality, experience and education. The teacher object should be able to perform actions (methods) like teach, create coursework, check assignments and take attendance. This object is a blueprint that can be used in the school program to create several other teachers with variations in attributes like names and methods like teaching methods.
Objects in object-oriented programming are self-contained or abstraction units of a program
The essential task of a program is to simplify a problem and offer a solution. In the pursuit of solving a problem, sometimes a program can become inherently complex and difficult to understand due to:
- number of instructions,
- nested structures, and
- dependencies.
This is especially true in the case of linear or procedural programming that focuses on writing sequences of instructions to be executed step-by-step. It exposes everything, making it harder to isolate problems, track logic, and scale systems efficiently. Abstraction, on the other hand, reduces such complexity by hiding internal details and exposing only what is necessary (MDN, 2025). It helps to model real-world systems in simpler and modular terms.
Imagine making food yourself in the kitchen versus ordering food in a restaurant. Just like procedural programming, you as a cook, will have to manage everything like chopping, cleaning, etc. In contrast, when you dine out, you simply place your order with a waiter and wait for the dish to arrive.

In OOP, the restaurant represents a system, and the waiter is the object that provides a clean interface for interaction. The kitchen, with all its internal processes, remains hidden, just like the internal logic and data within an object. This is known as abstraction, which exposes only what’s necessary while hiding the complexity underneath. This helps developers to build clean, modular programs where users interact with simple methods, without needing to understand the underlying implementation.
Data abstraction is the core concept of Object-Oriented Programming (OOP). It is essential for managing complexities or programming by hiding irrelevant details in large systems (Grady Booch et al., 2007). This helps to focus on high-level problems without being overwhelmed by low-level implementation details of a program. Objects provide the foundational building blocks for modeling, decomposing, and understanding complex systems. Below are two separate scripts that demonstrate the difference between procedural programming and object-oriented programming (OOP).
# Procedural programming just like cooking at home
def chop_vegetables(ingredients):
print(f"Chopping {ingredients}...")
def boil_water():
print("Boiling water...")
def cook(dish):
print(f"Cooking {dish} with available ingredients...")
def serve(dish):
print(f"Plating and serving {dish}.")
# Implementing
print("Cooking at home (Procedural):")
ingredients = "onions, tomatoes, and peppers"
dish = "Vegetable Curry"
chop_vegetables(ingredients)
boil_water()
cook(dish)
serve(dish)
print("Dinner is ready!")
Cooking at home (Procedural):
Chopping onions, tomatoes, and peppers...
Boiling water...
Cooking Vegetable Curry with available ingredients...
Plating and serving Vegetable Curry.
Dinner is ready!
The above code is sequential, where every step is clearly laid out and tightly coupled to its implementation. To make another dish, using this code, the user will need to manually change the code or copy its functions. This shows limited modularity because the functions aren’t grouped in a meaningful structure.
#OOP just like ordering food in a kitchen
class Kitchen:
def __init__(self, dish):
if dish == "Pasta":
self.ingredients = "onions, tomatoes, and peppers"
elif dish == "Paneer Butter Masala":
self.ingredients = "paneer, tomatoes, onions, butter and spices"
else:
self.ingredients = "unknown ingredients"
def prepare(self, dish):
print(f"Preparing {dish} in the kitchen...")
print(f"Ingredients are {self.ingredients}")
print(f"{dish} is ready!")
class Restaurant:
def order(self, dish):
print(f"Order received for: {dish}")
kitchen = Kitchen(dish)
kitchen.prepare(dish)
print(f"{dish} is served at your table.")
# Implementation
print("Ordering at a restaurant (OOP):")
# Abstracting the logic
waiter = Restaurant()
# Easily reuse the object for multiple dishes
waiter.order("Pasta")
waiter.order("Paneer Butter Masala")
# Abstracting the logic
waiter = Restaurant()
# Easily reuse the object for multiple dishes
waiter.order("Pasta")
waiter.order("Paneer Butter Masala")
Ordering at a restaurant (OOP):
Order received for: Pasta
Preparing Pasta in the kitchen...
Ingredients are onions, tomatoes, and peppers
Pasta is ready!
Pasta is served at your table.
Order received for: Paneer Butter Masala
Preparing Paneer Butter Masala in the kitchen...
Ingredients are paneer, tomatoes, onions, butter and spices
Paneer Butter Masala is ready!
Paneer Butter Masala is served at your table.
The functions defined inside a Class gets associated with that particular Class and are called methods. Similarly, attributes are variables such as self.ingredients are also defined in the Class for accessibility across the scope of the object.
The Restaurant object abstracts and organises responsibilities in the form of methods. The Kitchen class is modular, and it can be reused or extended for different dishes. The same structure handles multiple dishes, any number of times, emphasising its modularity.
The difference between encapsulation and abstraction in object-oriented programming (OOP)
Abstraction stems from identifying shared characteristics or patterns among objects, situations, or processes, while choosing to focus on these similarities and temporarily setting aside their differences. Encapsulation is achieved by concealing the internal details of an object that are not integral to its core characteristics. This process, known as information hiding, typically obscures the object’s structure and the implementation of its methods, ensuring a clear interface for interaction while safeguarding its complexity (Grady Booch et al., 2007). Encapsulation and abstraction are closely related in Object-Oriented Programming (OOP), but they are not the same. They work together, but they serve different purposes. While abstraction is about hiding code complexities to make usage easier (MDN, 2025), encapsulation is about hiding an object’s data and behaviour to protect it (Stroustrup, 1988). In other words, abstraction simplifies the interface; encapsulation secures the implementation.
In object-oriented programming, the data in a class is stored as attributes. They define the state of an object and can take on different values for different instances of the same class. The attributes help to distinguish between different instances of the same object. Without the attributes, the object will not have a context to operate on. Encapsulation is the bundling of data and the methods that operate on that data into a single unit (a class) and restricting direct access to some components of that unit.
In the school and teacher example, attributes are the nouns such as name, speciality, experience and education that describe the object’s state or features. There can be multiple instances of the teacher blueprint in the school program, distinguished by the name attribute.
class Teacher:
def __init__(self, name, gender, specialty, experience, education):
self.__name = name
self.__gender = gender
self.__specialty = specialty
self.__experience = experience
self.__education = education
# Getter and setter for name
@property
def name(self):
return self.__name
@name.setter
def name(self, new_name):
if new_name:
self.__name = new_name
# Private method
def __teaching_style(self):
return "interactive and student-focused"
# Public behaviors
def teach(self):
print(f"{self.__name} is teaching {self.__specialty} using {self.__teaching_style()} method.")
def create_coursework(self):
print(f"{self.__name} is creating coursework for {self.__specialty}.")
def check_assignments(self):
print(f"{self.__name} is checking assignments.")
def take_attendance(self):
print(f"{self.__name} is taking attendance.")
def get_teacher_profile(self):
return {
"Name": self.__name,
"Gender": self.__gender,
"Specialty": self.__specialty,
"Experience": f"{self.__experience} years",
"Education": self.__education
}
class School:
def __init__(self, school_name):
self.__school_name = school_name
self.__teachers = [] # private list of Teacher objects
def add_teacher(self, teacher_obj):
if isinstance(teacher_obj, Teacher):
self.__teachers.append(teacher_obj)
print(f"Teacher {teacher_obj.name} added to {self.__school_name}.")
else:
print("Only Teacher objects can be added.")
def list_teachers(self):
print(f"\nTeachers in {self.__school_name}:")
for teacher in self.__teachers:
profile = teacher.get_teacher_profile()
print(f"- {profile['Name']} ({profile['Specialty']})")
def conduct_classes(self):
print(f"\n{self.__school_name} is starting classes:")
for teacher in self.__teachers:
teacher.teach()
# Create school
my_school = School("Sunshine Public School")
# Create teacher objects
teacher1 = Teacher("Anita Sharma", "Female", "Mathematics", 12, "M.Sc. Mathematics")
teacher2 = Teacher("Rajiv Mehta", "Male", "History", 8, "M.A. History")
# Add teachers to school
my_school.add_teacher(teacher1)
my_school.add_teacher(teacher2)
# Use school methods
my_school.list_teachers()
my_school.conduct_classes()
Teacher Anita Sharma added to Sunshine Public School.
Teacher Rajiv Mehta added to Sunshine Public School.
Teachers in Sunshine Public School:
- Anita Sharma (Mathematics)
- Rajiv Mehta (History)
Sunshine Public School is starting classes:
Anita Sharma is teaching Mathematics using interactive and student-focused method.
Rajiv Mehta is teaching History using interactive and student-focused method.
In the Teacher class:
- The private attributes like
__name,__gender, etc., cannot be accessed directly outside the class and are encapsulated to protect the internal state of the object. - Getters and setters, such as
@propertyfor __nameprovides controlled access to private data. This ensures validation, formatting, or logging can be added later. - Private methods like
__teaching,__style()encapsulates internal logic that shouldn’t be accessible directly. It is used only inside other public methods liketeach(). - Public methods such as
teach()andcreate_coursework()defines the external interface that others, like theSchoolobject, are allowed to do with theTeacher.
In the School class:
- A private attribute such as
__teachersis a list storing teacher objects, hidden from the outside. This prevents direct tampering with the internal list. - Public method, such as the
add_teacher()adds teacher objects in a safe and controlled way. It ensures that only valid Teacher instances are added. - Public method like
list_teachers()reads from internal data but show only the necessary info. - The encapsulation of the school class is designed to avoid the necessity of knowing the specific methods employed by the teacher. Consequently, it simply invokes the method teacher.teach(). This approach conceals complexity through abstraction while ensuring protection of control and access via encapsulation.
Encapsulation keeps the data safe from accidental modification and maintains a clean and consistent interface even if the internals change. Therefore, the real-world logic is preserved as teachers do their job, and the school just manages them. By bundling data (attributes) and behaviour (methods) inside objects and restricting direct access to internal details, encapsulation ensures that each part of a program functions as an independent, well-defined unit. It’s a foundational principle that transforms simple scripts into scalable, professional-grade software.
How do inheritance and polymorphism enhance modularity and code reuse?
Modularity is dividing a large program into different modules reduces its complexity to some degree. Modules act as structural containers for defining the classes and objects within a logical design. In software design principles, each data structure is confined within its respective module. It is accessible only by programs within the module itself, ensuring that external programs cannot directly interact with it. To access the information encapsulated within a module’s data structure, external programs must rely on the module’s defined interface by invoking its designated programs. This controlled interaction promotes modularity and safeguards the integrity of the data, aligning seamlessly with encapsulation principles (Grady Booch et al., 2007). The principles of abstraction, encapsulation, and modularity work together to create coherent and maintainable systems. Abstraction defines a clear boundary around an individual concept, while encapsulation and modularity establish protective layers that safeguard and organise this concept effectively.

When you dine in a restaurant, you interact with the menu, place an order through the waiter and receive your food at the table. You don’t know or need to know how many chefs cooked it, the recipe, the technique, or the exact process or how the resources are managed in the kitchen. Here, hiding internal complexity behind the kitchen door is abstraction, and the menu and waiter are its interface. As chefs use confidential recipes, complex processes and hidden measurements that are only accessible to authorised staff, it is encapsulation. Moreover, there are other functional units of a restaurant, such as billing and reception, that operate independently but cooperatively. This is known as modularisation.
Furthermore, inheritance and polymorphism are core object-oriented programming (OOP) concepts that significantly enhance code reuse. Inheritance establishes a hierarchy among classes, enabling one class to adopt the attributes and functionalities outlined in another class, whether through single inheritance or multiple inheritance (Grady Booch et al., 2007). The class from which another class inherits can be called a parent class. In other words, inheritance enables subclasses to adopt the attributes and methods defined by their parent class. This means shared functionality is written once in the parent class and reused by all subclasses, reducing code duplication and promoting modularity.
Consider a Vehicle class as the parent class. It contains attributes like speed and capacity and methods such as start() and stop(). There can be subclasses like Car and Bike that inherit these attributes and methods from the Vehicle class. The Car class can have an additional attribute like airConditioning and a method like playMusic(), while the Bike class can have helmetLock attribute. Both subclasses reuse the shared functionality from the Vehicle class, such as start() and stop(), but extend it with features specific to their type.

Polymorphism on the other hand means “many forms”. It allows different classes to respond to the same method call in different ways. This enables objects of different classes to be treated as objects of a common superclass or interface.
Without polymorphism, developers are often forced to rely on cumbersome conditional constructs such as large case or switch statements to handle varied behaviors across different object types. These structures require explicit checks for every possible type or condition, leading to bloated and less maintainable code.
Imagine a “START” button:
- On a microwave, it begins heating.
- On a blender, it starts blending.
- On a car, it starts the engine.
The button is the same, but the behavior varies depending on the object.
Polymorphism streamlines processes by enabling objects to define their own unique behaviors for shared methods, thereby reducing conditional logic and fostering cleaner, more scalable code.
# Base class (Parent)
class Staff:
def __init__(self, name):
self.name = name
def start_shift(self):
print(f"{self.name} has started their shift.")
def perform_duty(self):
print(f"{self.name} is performing general duties.")
def end_shift(self):
print(f"{self.name} has ended their shift.")
# Subclass 1 - inherits from Staff
class Waiter(Staff):
def perform_duty(self):
print(f"{self.name} is taking orders and serving food.")
def greet_customers(self):
print(f"{self.name} says: Welcome to the restaurant!")
# Subclass 2 - inherits from Staff
class Chef(Staff):
def perform_duty(self):
print(f"{self.name} is preparing dishes in the kitchen.")
def prepare_special(self):
print(f"{self.name} is preparing today's special.")
# Subclass 3 - inherits from Staff
class Cashier(Staff):
def perform_duty(self):
print(f"{self.name} is managing the billing counter.")
def generate_invoice(self):
print(f"{self.name} is generating a customer's bill.")
# Polymorphic function
def run_shift(staff_member):
staff_member.start_shift()
staff_member.perform_duty() # Polymorphism in action
staff_member.end_shift()
# Main flow
if __name__ == "__main__":
staff_list = [
Waiter("Riya"),
Chef("Manoj"),
Cashier("Meena")
]
for staff in staff_list:
run_shift(staff)
print("---")
# Show reusability and modularity
# Each staff class can be extended without changing base logic
special_chef = Chef("David")
special_chef.prepare_special()
head_waiter = Waiter("Arjun")
head_waiter.greet_customers()
Riya is taking orders and serving food.
Riya has ended their shift.
---
Manoj has started their shift.
Manoj is preparing dishes in the kitchen.
Manoj has ended their shift.
---
Meena has started their shift.
Meena is managing the billing counter.
Meena has ended their shift.
---
David is preparing today's special.
Arjun says: Welcome to the restaurant!
The Waiter, Chef, and Cashier classes inherit from the Staff base class. They automatically get shared methods like start_shift() and end_shift(). They extend the functionality with specialized behavior like prepare_special(), greet_customers(). The function run_shift() uses the same method perform_duty() for all staff types. But each subclass overrides perform_duty() to behave differently, this is polymorphism. Each role such as Waiter, Chef, Cashier is implemented as its own independent module. The Staff base class can be reused across multiple roles like Cleaner.
In conclusion, inheritance and polymorphism are fundamental principles in object-oriented programming that enhance code reusability, modularity, and scalability. While inheritance provides a mechanism for subclasses to adopt and extend functionalities from parent classes, polymorphism enables objects to exhibit distinct behaviors for shared methods. Together, they reduce redundancy, streamline logic, and foster cleaner, more adaptive code structures, empowering developers to create versatile systems.
Reference
- Grady Booch, Robert A. Maksimchuk, Michael W. Engle, Bobbi J. Young, Jim Conallen, & Kelli A. Houston. (2007). Object-Oriented Analysis and Design with Applications, Third Edition[Book] (Third). Addison-Wesley. https://zjnu2017.github.io/OOAD/reading/Object.Oriented.Analysis.and.Design.with.Applications.3rd.Edition.by.Booch.pdf
- MDN. (2025, April 11). Object-oriented programming—Learn web development | MDN. MDN Web Docs. https://developer.mozilla.org/en-US/docs/Learn_web_development/Extensions/Advanced_JavaScript_objects/Object-oriented_programming
- Stroustrup, B. (1988). What is object-oriented programming? IEEE Software, 5(3), 10–20. https://doi.org/10.1109/52.2020
I am an interdisciplinary educator, researcher, and technologist with over a decade of experience in applied coding, educational design, and research mentorship in fields spanning management, marketing, behavioral science, machine learning, and natural language processing. I specialize in simplifying complex topics such as sentiment analysis, adaptive assessments and data visualizatiion. My training approach emphasizes real-world application, clear interpretation of results and the integration of data mining, processing, and modeling techniques to drive informed strategies across academic and industry domains.
Discuss