Encapsulation and Invariants
Low-Level Design: lesson 2 of 10
Hide the state so the object can never be caught in a bad one.
Lesson 2 of 10 · 5 min
Encapsulation and Invariants
Step 1 of 11
target21
An invariant is a promise that holds before and after every public call.
The Idea
An invariant is a promise about an object that holds before and after every public call. Encapsulation is how you keep it: fields stay private, and the only way in is a method that validates first. A rejected call changes nothing at all.
Real-World Example
A pressure cooker's locking lid. While there is pressure inside, the lid physically will not turn. You are not trusted to check the gauge yourself — the only route to an open pot runs through the release valve.
The Code
class Thermostat:
def __init__(self, target): self._target = 5; self.set(target)
def set(self, c):
if not 5 <= c <= 30: # the invariant, checked at the door
raise ValueError("outside safe range")
self._target = c
@property
def target(self): return self._target # read-only from outside
t = Thermostat(21)
t.set(24)
print(t.target) # 24
try: t.set(80)
except ValueError as e: print("refused:", e) # refused: outside safe range
print(t.target) # 24 -- still a legal state
Your turn
What does this print?
class Counter:
def __init__(self): self._n = 0
def add(self, k):
if k <= 0: return False
self._n += k
return True
c = Counter()
print(c.add(3), c.add(-1), c._n)Mini quiz
1 / 3