Object oriented programming
Every program is data, plus the code that changes it. The only real question is where
you keep the two. Keep them apart and, six months in, twelve functions across nine files
all edit the same order object, and nobody can tell you which one set the total to
zero.
Object oriented programming is one answer to that. Put the data and the code that is allowed to change it in the same place, and give that place a name.
You have probably heard there are four pillars of OOP. Without looking anything up, write down the ones you remember and one sentence on what each is for.
A class is a recipe, an object is the dosa
A class describes what a thing knows and what it can do. An object is one actual thing made from that description. One recipe, many dosas, and eating one does not change the others.
class Rider {
name: string
deliveries = 0
constructor(name: string) {
this.name = name
}
deliver(): void {
this.deliveries += 1
}
}
const asha = new Rider('Asha')
const ravi = new Rider('Ravi')
asha.deliver()
asha.deliver()
console.log(asha.deliveries) // 2
console.log(ravi.deliveries) // 0Four words carry this whole snippet. constructor runs once when an object is made.
new is what makes it. this is the particular object the method was called on, which
is why asha.deliver() did not touch Ravi’s count. And deliveries = 0 is a field with
a default, so TypeScript infers it is a number.
The four pillars
Each pillar is an answer to one question you will keep asking about your own code. Learn the question and the name looks after itself.
| Pillar | The question it answers | The picture |
|---|---|---|
| Encapsulation | Who is allowed to change this data? | An ATM |
| Abstraction | What does the caller need to know? | A switch on the wall |
| Inheritance | What do these types share? | A family recipe |
| Polymorphism | How does one call do different things? | The horn |
The first letters spell it. When an interviewer says “explain the four pillars”, say “A PIE” in your head and you will not drop one. Then answer with the question each one settles, which is what they are listening for.
All four in one screen
Do not try to learn the syntax here. Read the four comments, and notice that the pillars are not four separate features. They are four views of the same thirty lines.
// Abstraction: callers only know that a payment method can pay.
interface PaymentMethod {
pay(amount: number): string
}
class Wallet implements PaymentMethod {
// Encapsulation: nothing outside this class can touch the balance.
private balance = 500
pay(amount: number): string {
this.balance -= amount
return `Wallet paid ${amount}, ${this.balance} left`
}
}
class Card implements PaymentMethod {
pay(amount: number): string {
return `Card charged ${amount}`
}
}
// Inheritance: a credit card is a card, plus a little more.
class CreditCard extends Card {
override pay(amount: number): string {
return `${super.pay(amount)} on credit`
}
}
// Polymorphism: one call, three different behaviours.
const methods: PaymentMethod[] = [
new Wallet(),
new Card(),
new CreditCard(),
]
for (const method of methods) {
console.log(method.pay(200))
}
// > Wallet paid 200, 300 left
// > Card charged 200
// > Card charged 200 on creditThe loop at the bottom is the payoff. It does not know which kind of payment method it is holding, and it does not need to. Add a fourth kind next month and the loop does not change.
Coming from Java, people wrap every function in a class. In TypeScript you do not have
to. Plain data is a type. A calculation with no state is a function. Reach for a class
when you have state and rules that protect it, like a balance that must never go
negative. A class with no fields and one method is a function wearing a costume.
Which pillar is this?
class Rider { ... }deliveries = 0constructor(name: string)this.namenew Rider("Asha")PaymentMethod[]The four pages
Read them in this order. Each one uses the one before it.
Checkpoint
1. asha and ravi are both made from class Rider. asha.deliver() runs twice. What is ravi.deliveries?
2. Which pillar answers the question "who is allowed to change this data"?
3. You have a function that converts rupees to paise. It holds no state. What should it be in TypeScript?
Object oriented programming keeps data and the code that changes it in one place. A class is the description, an object is one thing made from it, and each object has its own state. There are four pillars and I remember them as A PIE. Encapsulation decides who can change the data, so the rules cannot be skipped. Abstraction decides what the caller needs to know, so the how can change freely. Inheritance lets types share behaviour that is written once. Polymorphism lets one call do the right thing for whichever object receives it, so the caller does not branch on type.
