Skip to main content

Objects, classes & interfaces

Every pattern on this site is a sentence written in one language: objects, interfaces, inheritance, composition. If that vocabulary is fuzzy, the patterns read like magic incantations - memorable, but unusable. Ten minutes here saves you the rest of the site.

Objects and classes

A class is a blueprint. An object is a thing built from it. The class says every cat has a name, a sex, an age and a color, and that every cat can breathe, sleep, run and meow. Your cat Oscar fills in the values.

Fields and methods together are the class's members. The data currently sitting in an object's fields is its state; what its methods let it do is its behavior. Oscar and your neighbor's Luna are the same class and completely different objects, because state is per-object and behavior is per-class.

Cat+ name+ gender+ age+ weight+ color...+ breathe()+ eat(food)+ run(destination)+ sleep(hours)+ meow()NameFieldsMethods(state)(behavior)Visibility+ = public- = privateThe ellipsis means there ismore in the class, but it isnot relevant at the moment.

Anatomy of a UML class box: one name, one block of state, one block of behavior.

Oscar: Catname="Oscar"sex="male"age=3weight=7color=browntexture=stripedLuna: Catname="Luna"sex="female"age=2weight=5color=graytexture=plain

Objects are instances of a class: same fields, different state.

Try it yourself: sketch a Car class instead of Cat - three fields and two methods it would need. Then imagine two Car objects side by side. What is different between them, and what is identical because it lives on the class rather than the object?

Enums

A class restricted to a fixed, named set of instances, decided once at compile time. Instead of passing the string "PENDING" around and misspelling it in one call site out of forty, you declare OrderStatus.PENDING and the compiler refuses to let anything else exist under that name.

«enum»OrderStatusPENDINGCONFIRMEDSHIPPEDDELIVEREDCANCELLED
An enum's members are the only instances that will ever exist.

Under the hood, an enum is still a class - the compiler just pre-builds exactly one object per named value and seals the constructor. That is why an enum constant can carry its own fields and override its own methods, the same as any other object:

// A raw int, and a comment doing the compiler's job.
class Order is
// status: 0 = pending, 1 = confirmed, 2 = shipped,
// 3 = delivered, 4 = cancelled
field status: int
 
method refundRate() is
if (status == 2 or status == 3)
return 0.5 // restocking fee once it has shipped
else
return 1.0
 
// Nothing stops status = 9, and nothing explains what 2 means
// to the next person who reads this file.
enum OrderStatus is
PENDING, CONFIRMED,
SHIPPED, DELIVERED, CANCELLED
 
method refundRate() is
switch (this) is
case SHIPPED, DELIVERED:
return 0.5 // restocking fee once it has shipped
default:
return 1.0
 
class Order is
field status: OrderStatus
 
// The rule that used to hide in a comment now lives on the
// type. There is no fifth status to misspell.

Two things this buys you that a raw constant cannot: the compiler rejects an out-of-range value at the call site instead of at 3 a.m. in production, and a switch over an enum can be checked for exhaustiveness, so adding RETURNED later surfaces every place that forgot about it. The price is symmetrical - adding a value means touching the enum's own declaration, which is exactly the kind of "vary here" instability the State pattern exists to route through polymorphism instead, once the per-constant behavior outgrows a switch.

Try it yourself: sketch an enum for a traffic light - RED, YELLOW, GREEN. Which method would you want each constant to override so its behavior differs per value, the way refundRate() differs per OrderStatus?

Interfaces

A contract with no implementation attached: a list of method signatures a class promises to honor, and nothing about how it honors them. A class describes what an object is. An interface describes what an object can do.

«interface»PaymentMethod+ pay(amount)+ refund(amount)CreditCard...PayPal...Crypto...
Three unrelated classes, one shared promise. None of them knows the others exist.

A checkout flow that holds a PaymentMethod reference never learns whether it is charging a card, debiting a wallet or moving a coin. Ship Apple Pay next year and the checkout code does not change - one more class keeps the same promise, and nothing that already worked notices the addition.

Interface vs abstract class

Both let you program to an abstraction, and both show up constantly in machine-coding interviews, which is exactly why the distinction gets asked about directly. The line:

  • Interface - a pure contract. No fields, no method bodies, no state. A class can implement as many interfaces as it likes, because promising to do several unrelated things costs nothing until you actually implement them.
  • Abstract class - part contract, part implementation. It can hold state and finished methods alongside the abstract ones subclasses must fill in. A class can extend exactly one, because it is inheriting real, concrete code, not just a signature.

Reach for an interface when unrelated classes need to promise the same behavior and nothing else - a Bird and an Airplane share zero code but can both promise fly(). Reach for an abstract class when subclasses genuinely share implementation and only differ in specific, well-defined places - that shared code is the entire reason to inherit.

An abstract class earns its keep the moment two subclasses would otherwise duplicate the same finished method. SalariedEmployee and HourlyEmployee both need to clockIn() and clockOut() in an identical way; only calculatePay() actually differs between them.

«abstract»Employee+ name+ id+ clockIn()+ clockOut()+ calculatePay()SalariedEmployee+ calculatePay()HourlyEmployee+ calculatePay()
The starred method is abstract - a promise. The other two are finished code every subclass gets for free.

That mix - some methods finished, one left as a promise - is exactly what an interface cannot offer, since an interface cannot finish any method at all.

Try it yourself: Shape needs Circle, Square and Triangle to all expose area(), sharing zero implementation. Separately, Employee needs SalariedEmployee and HourlyEmployee to share clockIn()/clockOut() but calculate pay differently. Which one gets an interface and which gets an abstract class, and why?

Class hierarchies

Once you notice dogs also have a name, a sex, an age and a color, and also breathe and sleep, the shared parts want a home. That home is a base class - Animal - with Cat and Dog extending it and contributing only their differences: meow() here, bark() there.

Animal+ name+ sex+ age+ weight+ color+ breathe()+ eat(food)+ run(destination)+ sleep(hours)Cat- isNasty: bool+ meow()Dog- bestFriend: Human+ bark()SuperclassArrows with empty triangleheads indicate inheritanceand always go from asubclass to a superclass.Arrows from severalsubclasses can overlap orbe drawn separately. Thisdoes not change their meaning.Subclasses
Every class here is part of the Animal hierarchy.

The parent is the superclass, the children are subclasses, and subclasses can override inherited methods either to replace the default behavior or to extend it. Push the idea one level up and Animal and Plant both descend from Organism. A Cat then inherits from everything above it. That stack is a hierarchy, and it is useful right up until the moment it is not - see Class relationships and Design principles for what replaces it once a hierarchy tries to model more than one dimension of variation.

OrganismAnimalPlantCatDog
Drop the compartments when the relations matter more than the contents.

Try it yourself: extend the Organism tree with a Fungus branch that shares almost nothing with Animal or Plant except being alive. At what point does forcing it under Organism start to feel like the wrong tool, and what would you reach for instead?

Check yourself

Question 1 of 4

Oscar and Luna are both Cat objects. What is different between them, and what is shared?