Encapsulation
Twice this month, Shelfwise showed a book with −2 copies in stock. Somewhere, some piece of code wrote book.stock = book.stock - 3 without checking first. Fourteen different places write to stock, and every one of them was trusted to remember the rule. Encapsulation removes that trust problem.
The rule
Hide the state; expose only operations that keep the rules.
Encapsulation has two halves:
- Hide an object's data so outside code cannot change it directly.
- Expose a small set of methods, and put the rules inside them.
class Book:
def __init__(self, title, stock):
self.title = title
self._stock = stock
@property
def stock(self):
return self._stock # anyone may read it
def reserve(self, qty):
if qty <= 0 or qty > self._stock:
raise ValueError("Cannot reserve that many copies")
self._stock -= qty
def restock(self, qty):
if qty <= 0:
raise ValueError("Restock amount must be positive")
self._stock += qtyNow the rule "stock never goes negative" lives in one place. Fourteen callers become fourteen calls to reserve(), and none of them can break the rule however they are written.
Languages enforce hiding differently. Java and C# have private and public keywords that the compiler checks. Python relies on convention: a leading underscore (_stock) means "internal, do not touch from outside". Either way, the design idea is the same.
Some fields have the strictest rule of all: never change after creation. A book's ISBN or an order's ID should be set once in the constructor and only ever read. Expose them as read-only properties with no method that alters them, and a whole family of "who changed the ID?" bugs disappears.
Encapsulation also frees you to change the inside later. If Shelfwise starts storing stock per warehouse, only Book changes; every caller still just calls reserve(qty).
The shortcut
For each field, ask: who may change this, and under what rule? If there is a rule, the field is private and a method enforces it. If there is no rule at all, it may be fine to leave it plain.
email
Must be a valid address. Rule exists, so make it
_emailwith achange_email(new)method that validates.
The trap is the "getter and setter for everything" habit. A private field with a set_stock(value) that accepts anything is not encapsulated; it is a public field with extra typing.
Drills
Answer fast — trust the rule.
What is the main goal of encapsulation?
In Python, what does a leading underscore in _stock signal?
Book has a private _stock and a method set_stock(value) that stores any value. Is stock encapsulated?
Shelfwise moves stock into several warehouses. Which code must change if Book is well encapsulated?
Remember
- Hide the state; expose only operations that keep the rules.
- Ask for each field: who may change it, under what rule?
- Trap: a setter that accepts anything is a public field in disguise.
