Skip to content
BytePatterns

Encapsulation and Invariants

Low-Level Design: lesson 2 of 15

Hide the state so the object can never be caught in a bad one.

Lesson 2 of 15 · 5 min

Encapsulation and Invariants

Step 1 of 11

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

Python

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

An invariant is:

New lessons land every few weeks

Leave an address and we will tell you when the next one is up. That is the only reason we will use it.

One address, stored so we can email you. Nothing else, ever.