Encapsulation
Data hiding, public vs private interfaces, cohesion, and why a well-encapsulated class is easier to use, test, and maintain. We extend Book and Customer and introduce ShoppingCart.
What objects are, how classes define them, and how instances come to life — through the lens of an online bookshop.
Software systems are built to represent and manage things from the real world. An online bookshop deals with books, customers, orders, and payments. Object-oriented design (OOD) gives us a principled way to translate those real-world things into software — one that is intuitive, maintainable, and extensible.
The core idea: identify the distinct things in your problem domain, describe what each one knows (data) and what each one can do (behaviour), then define the template (the class) from which any number of those objects can be created.
Throughout this course we model a single consistent domain. The table below shows every real-world thing we will represent, across all eight modules:
| Real-world thing | Class we will build |
|---|---|
| A book for sale | Book |
| A registered customer | Customer |
| A shopping basket | ShoppingCart |
| A purchase transaction | Order |
| One line on an order | OrderItem |
| A payment method | Payment |
| Stock levels | Inventory |
| A customer review | Review |
Table 1 — Real-world things and their software counterparts in the bookshop.
An object is a software entity that bundles two things together:
Every object in a running program has three fundamental properties:
| Property | Meaning |
|---|---|
| Identity | Each object is a distinct individual, even if two objects hold identical data. Two Book objects with the same title are still two separate objects. |
| State | The current values of the object’s attributes. State can change over time — a book’s stock decreases when a copy is sold. |
| Behaviour | What the object can do, expressed as methods. Behaviour is defined once in the class and shared by all instances. |
Table 2 — The three fundamental properties of every object.
A class is a blueprint. Just as an architect’s blueprint defines the layout of a building without being a building itself, a class defines the structure of an object without being an object. You can construct many buildings from one blueprint; you can create many objects from one class.
| Concept | Definition & Example |
|---|---|
| Attribute | A named slot for a piece of data. Every object has its own copy. Example: Book has isbn, title, author, price, stock. |
| Method | A named operation. Methods implement behaviour and typically read or modify the object’s attributes. Example: is_available() checks whether stock > 0. |
| Constructor | A special method called when an object is created. In Python: __init__. Initialises the object’s attributes to their starting values. |
Table 3 — Attributes, methods, and constructors.
class Book: """A book available for purchase in the bookshop.""" # ── Constructor ────────────────────────────────────── def __init__(self, isbn: str, title: str, author: str, price: float, stock: int = 0): # self refers to the specific object being created self.isbn = isbn # unique identifier self.title = title self.author = author self.price = price # selling price in GBP self.stock = stock # number of copies available # ── Methods ─────────────────────────────────────────── def get_details(self) -> str: """Return a human-readable summary of the book.""" return f"{self.title} by {self.author} £{self.price:.2f}" def is_available(self) -> bool: """Return True if at least one copy is in stock.""" return self.stock > 0 def apply_discount(self, percent: float) -> None: """Reduce the price by the given percentage (0–100).""" if not 0 <= percent <= 100: raise ValueError("Discount must be between 0 and 100") self.price *= (1 - percent / 100)
The Unified Modelling Language (UML) provides a standard graphical notation for classes. A class is drawn as a rectangle with three compartments: the class name, attributes, and methods. The visibility marker − means private; + means public.
Instantiation is the act of creating a concrete object from a class. In Python, you call the class by name and pass the constructor arguments. Each call produces a completely independent object with its own copy of every attribute.
# Create two Book objects from the same Book class book1 = Book( isbn = "978-0-13-110362-7", title = "The C Programming Language", author = "Kernighan & Ritchie", price = 45.99, stock = 12 ) book2 = Book( isbn = "978-0-20-163361-0", title = "The Pragmatic Programmer", author = "Hunt & Thomas", price = 39.99, stock = 0 # out of stock ) print(book1.get_details()) # "The C Programming Language by Kernighan & Ritchie £45.99" print(book1.is_available()) # True print(book2.is_available()) # False book1.apply_discount(10) # 10% off book1 only print(book1.price) # 41.391 print(book2.price) # 39.99 — book2 is unchanged
Two objects can hold exactly the same data yet be completely separate individuals — each with its own memory address, its own state that can change independently.
bookA = Book("978-0-13-110362-7", "The C Programming Language", "Kernighan & Ritchie", 45.99, 5) bookB = Book("978-0-13-110362-7", "The C Programming Language", "Kernighan & Ritchie", 45.99, 5) # Same data ... print(bookA.title == bookB.title) # True — same value # ... but different objects print(bookA is bookB) # False — different identity # Mutating one does not affect the other bookA.apply_discount(20) print(bookA.price) # 36.792 print(bookB.price) # 45.99 — unchanged
| Operator | Tests |
|---|---|
== | Value equality — do the objects’ contents match? |
is | Identity — are the two variables pointing to the exact same object in memory? |
Table 4 — == tests value; is tests identity.
== when is was intended, or vice versa. For custom classes, == falls back to identity comparison unless you define __eq__. We revisit this in Module 3 when we implement __eq__ properly.
book1 and book2 are two distinct instances of Book, each with its own state. customer1 is an independent instance of Customer.| Diagram type | Shows |
|---|---|
| Class diagram | The blueprint — class name, attribute names and types, method signatures. No specific values. |
| Object diagram | A snapshot — specific named objects with concrete attribute values. Header is underlined and written as objectName : ClassName. |
Table 5 — Class diagram vs object diagram.
− for private, + for public, # for protected. In an object diagram, attribute values are shown without visibility markers — we are looking at a snapshot, not a definition.
The definition/usage distinction in SysML v2 is a direct generalisation of the class/object distinction. The correspondence is precise:
part defpartattributeaction def / action:=part myBook : Book// SysML v2 equivalent of the Book class part def Book { attribute isbn : String; attribute title : String; attribute author : String; attribute price : Real; attribute stock : Integer := 0; action def get_details : String; action def is_available : Boolean; action def apply_discount { in percent : Real; } } // Using (instantiating) the Book definition part book1 : Book { :>> isbn = "978-0-13-110362-7"; :>> title = "The C Programming Language"; :>> author = "Kernighan & Ritchie"; :>> price = 45.99; :>> stock = 12; }
part usages are model-time declarations — they describe specific, named elements of the system architecture, not runtime heap allocations. The structural analogy holds; the execution semantics differ.
An object bundles state (data) and behaviour (methods) together. This bundling is called encapsulation.
A class is a blueprint. It defines attributes and methods that all objects of that type will have. It is not itself an object.
Creating an object from a class. One class — unlimited objects, each with its own independent state.
Every object has identity (unique individual), state (current attribute values), and behaviour (methods).
Two objects can hold identical data yet remain separate. == tests value equality; is tests identity.
Class → part def. Object → part. The definition/usage distinction is a direct generalisation.
Data hiding, public vs private interfaces, cohesion, and why a well-encapsulated class is easier to use, test, and maintain. We extend Book and Customer and introduce ShoppingCart.