What Is Object-Oriented Programming? Concepts Explained With One Example
Classes, objects, inheritance, encapsulation and polymorphism explained in plain English, using one running example of a coffee shop loyalty app.
Object-oriented programming (OOP) is a way of writing software that groups data and the actions on that data into objects built from templates called classes. Its 4 core ideas are encapsulation, inheritance, polymorphism and abstraction. Languages such as Java, Python, C#, C++ and JavaScript all support it.
Photo: Unsplash
On this page
If you’ve started learning to code, or you sit in meetings with developers, you’ve heard the phrase “object-oriented.” It shows up in job posts, coding interviews and architecture debates. Yet most explanations jump straight into abstract definitions about “instances” and “polymorphism” that don’t stick.
This guide takes a different route. We’ll build one small piece of software, a loyalty program for a coffee shop, and introduce each OOP concept exactly when we need it. By the end, you’ll know what classes, objects, inheritance and encapsulation are, and why so many teams organize their code this way.
What object-oriented programming means
Object-oriented programming (OOP) is a style of programming that organizes code around objects. An object bundles together 2 things:
- State: the data the object holds, such as a customer’s name or point balance.
- Behavior: the actions the object can perform, such as adding points or redeeming a reward.
Oracle’s Java tutorial describes an object as “a software bundle of related state and behavior,” which is as good a one-line definition as any.
The alternative most people learn first is procedural programming, where data sits in one place and separate functions act on it. That works well for small scripts. As programs grow, though, it gets harder to know which function is allowed to change which data. OOP’s answer is to keep the data and the code that changes it together.
The ideas go back further than many people expect. Ole-Johan Dahl and Kristen Nygaard received the 2001 ACM Turing Award for ideas fundamental to the emergence of object-oriented programming, through their Simula I and Simula 67 languages. Alan Kay received the 2003 Turing Award in part for pioneering many of the ideas at the root of today’s object-oriented languages and leading the team that developed Smalltalk.
Classes and objects: the coffee shop example
Imagine a coffee shop wants a loyalty program. Every customer has an account, earns points per purchase and can redeem points for a free drink.
A class is the template that describes what every loyalty account looks like. An object (also called an instance) is one specific account built from that template. Here’s the class in Python:
```python class LoyaltyAccount: def init(self, name): self.name = name self.points = 0
def add_purchase(self, amount):
self.points += int(amount)
def redeem_drink(self):
if self.points >= 100:
self.points -= 100
return True
return False
```
And here are 2 objects created from it:
```python maria = LoyaltyAccount(“Maria”) james = LoyaltyAccount(“James”)
maria.add_purchase(12.50) ```
A few terms to know:
__init__is the constructor. It runs when a new object is created and sets its starting state.nameandpointsare attributes (the state).add_purchaseandredeem_drinkare methods (the behavior).mariaandjamesare separate instances. Maria’s points don’t affect James’s.
Think of the class as a cookie cutter and each object as a cookie. One template, as many accounts as you need.
The 4 pillars of OOP, using the same example
With the basic class in place, the 4 core ideas of OOP each solve a specific problem the coffee shop will run into.
Encapsulation: protecting the data
Right now, any part of the program can write maria.points = 5000 and hand her 50 free drinks. That’s a problem.
Encapsulation means an object keeps its internal state private and exposes a controlled public interface. Other code asks the object to do things through its methods rather than changing its data directly.
```python class LoyaltyAccount: def init(self, name): self.name = name self._points = 0
def add_purchase(self, amount):
if amount <= 0:
raise ValueError("Purchase must be positive")
self._points += int(amount)
def balance(self):
return self._points
```
The rule for earning points now lives in one place. If the shop changes its policy, you change one method and every part of the app follows.
How strictly this is enforced depends on the language. Java, C# and C++ have a private keyword that makes outside access an error. Python relies on convention: the official Python tutorial notes that truly private instance variables don’t exist, and a leading underscore signals “internal, don’t touch.”
Key takeaway: Encapsulation isn’t about secrecy. It’s about having one trusted place where the rules for changing data live, so bugs can’t sneak in from 20 different directions.
Inheritance: reusing what you built
The shop launches a Gold tier. Gold members earn double points but otherwise work exactly like regular members. Copying the whole class would mean maintaining 2 versions of the same code.
Inheritance lets a new class (the subclass or child) build on an existing one (the superclass or parent), reusing everything and changing only what’s different:
python
class GoldAccount(LoyaltyAccount):
def add_purchase(self, amount):
if amount <= 0:
raise ValueError("Purchase must be positive")
self._points += int(amount) * 2
GoldAccount automatically gets name, balance() and redeem_drink() from its parent. Only add_purchase is rewritten. Writing a new version of an inherited method like this is called overriding.
Inheritance is powerful, but it’s easy to overuse. Deep chains of classes inheriting from classes inheriting from classes become hard to follow. Many experienced developers prefer composition, where an object holds other objects rather than inheriting from them, for anything beyond a simple “is a kind of” relationship. A Gold account clearly is a kind of loyalty account, so inheritance fits here.
Polymorphism: one call, different behavior
At checkout, the point-of-sale code doesn’t need to know which tier a customer is in:
python
for account in [maria, james, priya_gold]:
account.add_purchase(8.00)
Each object responds in its own way: regular accounts add 8 points, Gold accounts add 16. That’s polymorphism, from the Greek for “many forms.” The same method call produces behavior suited to each object’s class.
The practical win is that you can add a Platinum tier next year without touching the checkout code at all. You write a new subclass, and everything that calls add_purchase keeps working.
Abstraction: hiding the complexity
Abstraction means showing only what other code needs to know and hiding the rest. The cashier’s screen calls redeem_drink(). It doesn’t need to know how points are stored, whether there’s a database involved or how fraud checks work.
Abstraction and encapsulation are close cousins. Encapsulation protects the data; abstraction simplifies the interface. Many languages formalize abstraction with interfaces or abstract classes: a contract that says “any loyalty account must have add_purchase and balance,” without saying how. Oracle’s Java tutorial describes an interface as a contract between a class and the outside world.
The 4 pillars at a glance
| Concept | Plain-English meaning | In the coffee shop example |
|---|---|---|
| Encapsulation | Keep data private; change it only through methods | Points can only change via add_purchase and redeem_drink |
| Inheritance | Build a new class on top of an existing one | GoldAccount reuses everything from LoyaltyAccount |
| Polymorphism | Same method call, different behavior per class | add_purchase(8) adds 8 or 16 points depending on tier |
| Abstraction | Expose what’s needed, hide the details | The register calls redeem_drink() without knowing how points are stored |
OOP across popular languages
Most mainstream languages support OOP, but they lean into it differently.
| Language | How it handles OOP |
|---|---|
| Java | Strongly class-based; nearly all code lives inside classes |
| C# | Class-based, similar to Java, with properties and interfaces built in |
| Python | Supports classes and multiple inheritance; privacy by convention |
| JavaScript | Prototype-based underneath, with class syntax added on top |
| TypeScript | Adds types, interfaces and access modifiers to JavaScript classes |
| C++ | Supports OOP alongside procedural and generic programming |
MDN’s JavaScript guide points out that JavaScript’s prototype model works more like delegation than classical inheritance, even when you write class. If you’re weighing languages, see Python vs JavaScript and TypeScript vs JavaScript.
OOP isn’t the only option. Functional programming, which favors pure functions and data that doesn’t change, has grown in popularity, and most modern codebases mix both styles.
When OOP helps and when it doesn’t
OOP tends to help when:
- You’re modeling real-world things with clear state and rules: customers, orders, invoices, devices.
- A team of developers needs clear boundaries between parts of the code.
- You expect to add new variations (like new tiers) over time.
It can get in the way when:
- You’re writing a short script or data-processing pipeline where plain functions are simpler.
- Class hierarchies grow deep and tangled, which is a common source of technical debt.
- Objects hide so much that it’s hard to tell what changed and where.
Where to start learning OOP
- Pick one language and stick with it. Our guide to choosing your first programming language can help.
- Write one class that models something you know: a recipe, a bank account, a to-do item.
- Add encapsulation by making state private and adding methods that enforce rules.
- Create one subclass that overrides a single method.
- Loop over a mix of objects and call the same method to see polymorphism in action.
- Read real code in an open-source project and spot the 4 pillars.
Free resources like the official Python tutorial and Oracle’s Java tutorials cover all of this. Our 6-month plan to learn to code for free fits OOP into a wider learning path, and OOP questions are common in coding interviews.
Conclusion
Object-oriented programming is simply a way to keep data and the rules for that data together. Classes are templates, objects are the things built from them, and the 4 pillars (encapsulation, inheritance, polymorphism and abstraction) keep growing codebases manageable. Build the coffee shop example yourself in 30 minutes, and the vocabulary will stop feeling abstract. For more terms like these, browse our glossary.
Sources
- Oracle Java Tutorials: Object-Oriented Programming Concepts — definitions of object, class, inheritance and interface
- Python documentation: Classes — Python class features, inheritance and the underscore privacy convention
- MDN Web Docs: Object-oriented programming — classes, encapsulation, polymorphism and how JavaScript prototypes differ
- ACM A.M. Turing Award: Ole-Johan Dahl — 2001 award for Simula I and Simula 67
- ACM Award Recipient: Alan Kay — 2003 award citation for object-oriented ideas and Smalltalk
Frequently asked questions
What is object-oriented programming in simple terms?
Object-oriented programming is a way of writing code where you group related data and actions into objects. You define a class as a template, such as "loyalty account," then create objects from it, such as Maria's account and James's account. Each object holds its own data and has methods that control how that data changes.
What are the 4 pillars of object-oriented programming?
The 4 pillars are encapsulation, inheritance, polymorphism and abstraction. Encapsulation keeps data private behind methods. Inheritance lets a new class reuse an existing one. Polymorphism lets the same method call behave differently for different classes. Abstraction hides complex details behind a simple interface that other code can use.
What is the difference between a class and an object?
A class is a template or blueprint, and an object is a specific thing built from it. The `LoyaltyAccount` class describes what every account has, a name and a point balance, and what it can do. Maria's account and James's account are 2 separate objects created from that class, each with its own data.
Is Python an object-oriented language?
Yes. Python fully supports object-oriented programming, including classes, inheritance, multiple inheritance and method overriding. Everything in Python, from numbers to functions, is an object. Python is also flexible, so you can write procedural or functional code without classes. It enforces privacy by convention, using a leading underscore, rather than with a private keyword.
Is JavaScript object-oriented?
Yes, but differently from Java or C#. JavaScript is prototype-based: objects link to other objects and delegate behavior to them. Since 2015, JavaScript has offered `class` syntax that looks like classical OOP, but it still runs on prototypes underneath. In practice, you can write object-oriented JavaScript, functional JavaScript or a mix of both.
What is the difference between OOP and functional programming?
OOP groups data and behavior into objects that can change state over time. Functional programming favors pure functions that take input and return output without changing shared data. OOP often suits modeling business entities, while functional style suits data transformations. Most modern languages support both, and many real codebases combine them.
Do I need to learn OOP to get a programming job?
For most developer roles, yes. Java, C#, Python, TypeScript and Kotlin codebases rely heavily on classes and objects, and OOP questions are common in technical interviews. You don't need to master every design pattern first. Start by understanding classes, objects and the 4 pillars, then practice by building small projects.
Was this guide useful
No reviews yet. Share your experience and help other readers.