Code Companion
Java

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.

IB DP CS standard B3.1.5: Explain and apply encapsulation and information hiding through private and public access, controlled class members and protection of valid object state.

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.

Python language difference: Python does not enforce Java-style 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 memberMeaning hereExample
publicPart of the interface other code is allowed to use.borrow(), getStatus()
privateImplementation state or helper behaviour restricted to the class.borrowed, title
Python namingMeaning hereImportant limitation
nameNormal public attribute or method.External access is expected.
_nameConvention: intended for internal/subclass use.Not enforced by the language.
__nameTriggers 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

LibraryBook
- title: String- borrowed: boolean
+ LibraryBook(title: String)+ borrow(): boolean+ returnBook(): boolean+ getStatus(): String
The loan state is private; callers request meaningful operations through the public interface.
LibraryBook
- __title: str- __borrowed: bool
+ __init__(title)+ borrow(): bool+ return_book(): bool+ get_status(): str
The UML expresses intended visibility. Double underscores provide name mangling for this classroom model, not absolute privacy.
The important feature is not merely hiding borrowed. The methods preserve the rule: an impossible request is rejected and the previous valid state remains unchanged.

Check the library boundary

Answer each question before opening the model answer.

  1. 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.

  2. 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.

  3. 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

ruleuse(amount)
checks before changing charge
visibilityget charge
reports without unrestricted mutation
lockinternal charge
state governed by the object
Valid-state rule: charge must never be negative. Every construction and state-changing path must preserve that rule.
EnergyCell
- charge: int
+ EnergyCell(initialCharge: int)+ use(amount: int): boolean+ getCharge(): int
Minus marks private state; plus marks the public interface.
EnergyCell
- __charge: int
+ __init__(initial_charge)+ use(amount): bool+ get_charge(): int
The UML expresses intended visibility. Python implements the classroom boundary with name mangling and controlled methods.

Apply the boundary in Java

Apply the boundary in Python

Trace every path

RequestCheckResultCharge after request
create with 12not negativeobject created12
use(5)positive and enough chargetrue7
use(20)insufficient chargefalse7 — unchanged
use(0)not positivefalse7 — 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.

  1. 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.

  2. 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.

  3. 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

Challenge ID: PC-T21-C01 · Standards: B3.1.5

Create 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.

Scaffold available
A LibraryBook object protecting internal state behind borrow, return and status operations.

Product Class

Challenge ID: PC-T21-C02 · Standards: B3.1.5

Create 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.

Scaffold available
A Product class with private code, name and price plus controlled public methods.

Temperature Sensor

Challenge ID: PC-T21-C03 · Standards: B3.1.5

Create 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.

Scaffold available
A TemperatureSensor object protecting an internal reading through validated public methods.

Password Vault Model

Challenge ID: PC-T21-C04 · Standards: B3.1.5, B2.3.2, B2.3.4

Build 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.

Scaffold available
A password-vault model with private stored data and controlled checking and update operations.

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.