Programming technique · B3.1.5
Encapsulation and information hiding
An object should own the rules that protect its state. External code uses a deliberate interface instead of changing the internal representation without checks.
What you need to be able to do
Identify the boundary
Distinguish internal state from the public operations other code should use.
Protect valid state
Validate construction and every state-changing path so the object cannot be left in an impossible condition.
Explain the design
Connect encapsulation and information hiding to maintainability, controlled access and clear responsibility.
Why should the object control its own state?
Return to the library example. A book starts available. After it is borrowed, borrowing it again should fail. Returning an already available book should also fail.
Unsafe approach
Any caller directly writes the borrowed value whenever it wants. The class cannot guarantee that changes follow the library's rules.
Controlled approach
Call borrow() and returnBook()/return_book(). The object checks its current state before changing anything.
Valid-state rule
A book is either available or borrowed, and only a valid operation should move it between those states.
private and public access modifiers. A leading underscore signals internal use; double underscores trigger name mangling. Good encapsulation still depends on a deliberate interface and valid-state rules, not on pretending access is impossible.Public interface and internal representation
| Java member | Meaning here | Example |
|---|---|---|
public | Part of the interface other code is allowed to use. | borrow(), getStatus() |
private | Implementation state or helper behaviour restricted to the class. | borrowed, title |
| Python naming | Meaning here | Important limitation |
|---|---|---|
name | Normal public attribute or method. | External access is expected. |
_name | Convention: intended for internal/subclass use. | Not enforced by the language. |
__name | Triggers name mangling and discourages accidental direct access. | It is not absolute privacy or security. |
UML can still express the intended design boundary: + marks public members and − marks private members.
Worked progression: LibraryBook now protects its loan state
- title: String- borrowed: boolean + LibraryBook(title: String)+ borrow(): boolean+ returnBook(): boolean+ getStatus(): String - __title: str- __borrowed: bool + __init__(title)+ borrow(): bool+ return_book(): bool+ get_status(): str Check the library boundary
Answer each question before opening the model answer.
-
Why is making borrowed private/internal not enough by itself?
Reveal model answer
Because a public method could still change it incorrectly. Encapsulation works only when every allowed state-changing path preserves the object’s rules.
-
Why is borrow() better than a general setBorrowed(true/false) operation?
Reveal model answer
borrow() expresses the real domain action and can enforce the rule that only an available book may become borrowed. A general setter exposes more mutation than the caller needs.
-
If the second borrow() call is rejected, what should happen to the object state?
Reveal model answer
Nothing should change. The book remains borrowed and the method reports failure.
Generalise the idea: the object owns the rule
Caller
Requests an operation
EnergyCell boundary
checks before changing charge
reports without unrestricted mutation
state governed by the object
- charge: int + EnergyCell(initialCharge: int)+ use(amount: int): boolean+ getCharge(): int - __charge: int + __init__(initial_charge)+ use(amount): bool+ get_charge(): int Apply the boundary in Java
Apply the boundary in Python
Trace every path
| Request | Check | Result | Charge after request |
|---|---|---|---|
| create with 12 | not negative | object created | 12 |
use(5) | positive and enough charge | true | 7 |
use(20) | insufficient charge | false | 7 — unchanged |
use(0) | not positive | false | 7 — unchanged |
Encapsulation and information hiding are related
Encapsulation
Keep state and the behaviour responsible for that state together inside a class boundary.
Information hiding
Limit reliance on the internal representation so callers depend on deliberate operations instead.
Hidden state alone is not enough
An unsafe method can still place internal state into an invalid condition.
Do not create setters automatically
Expose operations that match responsibility rather than unrestricted writes for every attribute.
Getters are a design choice too
Expose information the caller actually needs. A getter is not automatically required for every hidden field.
Security has a boundary
Access control and conventions protect program design; they do not automatically provide encryption or authentication.
Can you protect valid state?
Answer each question before opening the model answer.
-
A Product price must always be greater than zero. Where must that rule be checked?
Reveal model answer
At every path that can establish or change the price: construction and every allowed update operation.
-
A TemperatureSensor rejects an invalid reading. Should the old reading be erased?
Reveal model answer
No. A rejected request should leave the previous valid state unchanged.
-
Does Python __balance make a bank balance secure or encrypted?
Reveal model answer
No. Double underscores trigger name mangling and discourage accidental access; they are not encryption, authentication or absolute privacy.
Apply a controlled interface
Choose a challenge and identify the valid-state rule before coding. Your public methods should represent meaningful operations, reject invalid requests and preserve the previous valid state when a request fails.
Challenges Choose one
Choose a challenge that feels appropriate for you. Code heat is only a rough estimate, not a fixed level.
Library Book
SelectedCreate a LibraryBook class with private title and borrowed state. External code must use public borrow, returnBook and getStatus operations rather than changing fields directly. Reject impossible repeated borrow or return requests and prove that rejected requests leave the object in a valid state.
Product Class
SelectedCreate a Product class with private code, name and price fields. The constructor and updatePrice method must preserve the rule that price is greater than zero. Provide a returning summary operation, test accepted and rejected changes and explain why private fields alone would not help if public methods allowed invalid values.
Temperature Sensor
SelectedCreate a TemperatureSensor with one private reading and a documented valid range. Validate the starting value, provide a guarded updateReading command and a read-only getTemperature query. Test both boundaries and prove that a rejected update does not alter the previous valid state.
Password Vault Model
SelectedBuild a classroom PasswordVault model with one private stored code. Public methods may check an attempt and update the code only when the current code is correct and the replacement satisfies a documented rule. Never return the stored code. Explain that private access supports information hiding inside this program but is not encryption or complete real-world password security.
Selected challenge
This choice is shared with the portfolio setup page.
Plan your solution in handwritten pseudocode
Before opening your IDE or writing any program code, handwrite pseudocode for this challenge on paper.
Not marked complete. If you submit now, the GitHub README will record “No”.
Create your challenge folder
Run this command after planning. It creates the correct empty folder inside your portfolio.
Complete the challenge
Use your handwritten pseudocode as the starting plan, then write and test your solution in the folder created above.
Optional two-level scaffold
Try from your handwritten pseudocode first. Scaffold gives some structure; Scaffold + comments gives stronger guidance. Use only the level you need, and update your pseudocode first if the support changes your plan.
Submit for review
Run this when your program is complete. It creates the README, commits the folder and pushes it. The README records whether you marked the handwritten pseudocode as complete; the paper itself is handed to your teacher separately.
Shared OOP teaching sequence complete
You have evaluated OOP, designed and instantiated classes, distinguished class-owned and instance-owned members, and applied controlled state boundaries. Students who are ready can choose an Additional Challenge while classmates catch up or revisit earlier work. The checkpoint exam itself is run separately by the teacher in class.