This content can't be printed from the browser. Use Export PDF with Pro for an offline copy.
IB Syllabus Requirements for Fundamentals of OOP for a single class
B3.1.1
Evaluating object-oriented programming
B3.1.2
Designing classes and their behaviour
B3.1.3
Static and instance members
B3.1.4
Defining classes and creating objects
B3.1.1
EVALUATING OBJECT-ORIENTED PROGRAMMING
Evaluating OOP means asking whether organizing a solution around objects fits the problem. Objects don't automatically make a program better.
Object-oriented programming (OOP) organizes a program around objects, combining state with operations on that state.
A class defines the attributes and methods shared by a kind of object. Each object is a particular instance of a class and has its own state.
An attribute stores a characteristic of an object, while a method defines an operation associated with a class or its objects.
Consider an equipment library. A class called LoanItem could describe anything available to borrow, with attributes such as label and available and methods such as borrow() and returnItem(). A camera labelled “Camera” and a projector labelled “Projector” would be separate objects. Borrowing the camera changes its availability; the projector's availability stays the same.
Inheritance allows a class to derive attributes and methods from another class. This suits an “is a kind of” relationship: a Camera, for example, is a specialized LoanItem.
Encapsulation combines state and the operations on that state within a class, while controlling access to its members. A borrowing operation, for instance, can prevent an item already on loan from being borrowed again.
Polymorphism allows the same operation to behave differently for different kinds of object. Calling describe() could produce a camera-specific description for a Camera and a projector-specific description for a Projector.
Camera and Projector inherit common features from LoanItem. Each supplies its own behaviour for describe(): inheritance provides the shared structure, while polymorphism allows behaviour to vary.
| Aspect | Potential advantage | Potential disadvantage |
|---|---|---|
| Modelling | Objects can reflect the entities and responsibilities in a problem. | Forcing a simple calculation into an object model can make it harder to follow. |
| Maintenance | Keeping related state and behaviour together makes changes easier to locate. | Poorly chosen responsibilities can spread one change across several classes. |
| Reuse | Classes and inherited features can avoid repeated implementation. | Inherited dependencies can cause a change in one class to affect other classes. |
| Integrity | Controlled methods can prevent invalid changes to an object's state. | Protection needs careful design; classes alone do not guarantee valid state. |
| Extensibility | Through polymorphism, different object types can support a common operation. | Adding classes and interacting behaviours can make execution harder to trace. |
| Resources | Reusable objects can give a substantial application a clear structure. | Creating objects and calling methods can introduce resource overhead, depending on the language and implementation. |
An equipment-loan application is a strong candidate for OOP. It has many items with independent state, along with repeated operations and rules that must remain consistent. Keeping each item's state and borrowing behaviour together makes those responsibilities explicit.
For a short program that reads a few values, calculates a total and prints it, a sequence of functions may be clearer. Several classes would add design work without necessarily improving the solution.
OOP suits many complex problems, but complexity alone isn't a sufficient reason to choose it. A stronger justification is that interacting objects give the problem a clear, maintainable structure.
Terms to use: classes, objects, inheritance, encapsulation, polymorphism, advantages and disadvantages.
B3.1.2
DESIGNING CLASSES AND THEIR BEHAVIOUR
Constructing a class design turns application requirements into named classes with stored attributes, operations and relationships. Before implementation begins, the design must make clear what each object knows and what it can do.
Consider these requirements for an equipment library:
Two classes emerge from these entities: LoanItem and Member. Values that need to be remembered become attributes; actions that inspect or change them become methods.
| Class | Attributes | Methods and responsibilities |
|---|---|---|
LoanItem | label: String; available: boolean | borrow(member: Member): boolean attempts a loan and reports success; returnItem(): void ends the loan; isAvailable(): boolean reports availability. |
Member | memberId: String | getMemberId(): String supplies the identifier. |
Give each behaviour to the class responsible for the state it affects. Because LoanItem owns the availability state, it should decide whether it can be borrowed. Code elsewhere shouldn't have to repeat that rule.
Unified modelling language (UML) is a standardized notation for representing software designs. A UML class diagram shows the structure of classes and the relationships between them. It doesn't require complete program code.
A class box has three compartments: one for the class name, one for attributes and one for methods. Write an attribute as a name followed by its type. For a method, show its name, parameters and return type. The visibility symbol - means private, while + means public. A return type of void means that the method returns no value.
LoanItem, the entries are - label: String, - available: boolean, + borrow(member: Member): boolean, + returnItem(): void and + isAvailable(): boolean. The Member box contains - memberId: String and + getMemberId(): String.
An association labelled borrows connects the two classes. The multiplicities express the requirements:
0..* at the LoanItem end means that one member may currently borrow zero or more items.0..1 at the Member end means that one item has zero or one current borrower.Read multiplicity at the opposite end of the relationship. Start with one member, then look toward the item end to find how many items that member may borrow.
Naming an operation isn't enough. A useful design also states what it does to the object's state.
| Operation | Starting condition | Result and state change |
|---|---|---|
borrow(member: Member) | The item is available. | Record the member as the current borrower, set availability to false and return true. |
borrow(member: Member) | The item is unavailable. | Leave the state unchanged and return false. |
returnItem() | The item is on loan. | Remove the current-borrower association and set availability to true. |
isAvailable() | Any valid state. | Return the current availability without changing it. |
You can check this design against the requirements before coding. The multiplicity, for example, rules out a design that permits two current borrowers for one item. The method behaviour specifies how to handle a rejected borrowing attempt.
Terms to use: classes, methods, behaviour, application requirements, unified modelling language (UML), class diagrams, class relationships, attributes.
B3.1.3
STATIC AND INSTANCE MEMBERS
Distinguish static and non-static members by asking who owns them: the class as a whole, or an individual object. Then check whether an operation needs a particular object's state.
A static variable, or class variable, belongs to the class rather than separately to each instance. An instance variable belongs to an individual object.
A static method is associated with the class and can be called without an instance. An instance method operates in the context of a particular object.
| Feature | Static or class member | Non-static or instance member |
|---|---|---|
| Variable ownership | One shared class-level value. | A separate value for each object. |
| Appropriate data | Information about the class as a whole, such as the total number of objects created. | Information that can differ between objects, such as an item's label. |
| Method call | Through the class name. | Through a reference to an object. |
| Access to state | No automatic access to a particular object's instance variables. | Can access the receiving object's state and shared class state. |
| Object required? | Not for a class-level call. | Yes: the call needs a receiving object. |
Ownership and visibility are different questions. Static does not mean public, and non-static does not mean private.
LoanItem owns its own label, while the class stores the number of items created. The figure shows two labels but only one shared counter: after creating “Camera” and “Tripod”, the counter is 2.
The Java and Python versions perform the same steps. The fields are left directly accessible here so that the ownership distinction is visible; controlled access is developed separately below.
1 public class LoanItem {
2 public static int totalItems = 0;
3 public String label;
4 public LoanItem(String label) {
5 this.label = label;
6 totalItems++;
7 }
8 public String getLabel() {
9 return label;
10 }
11 public static int getTotalItems() {
12 return totalItems;
13 }
14 public static void main(String[] args) {
15 LoanItem first = new LoanItem("Camera");
16 LoanItem second = new LoanItem("Tripod");
17 System.out.println(first.getLabel());
18 System.out.println(LoanItem.getTotalItems());
19 }
20 }
1 class LoanItem:
2 total_items = 0
3 def __init__(self, label):
4 self.label = label
5 LoanItem.total_items += 1
6 def get_label(self):
7 return self.label
8 @staticmethod
9 def get_total_items():
10 return LoanItem.total_items
11 first = LoanItem("Camera")
12 second = LoanItem("Tripod")
13 print(first.get_label())
14 print(LoanItem.get_total_items())
In Java, static explicitly marks the shared field and class-level method. The instance method reads the label of the object on which it was called.
In Python, assigning total_items in the class body creates a class attribute. Updating it through LoanItem changes the shared value. Assigning through an instance can instead create an instance attribute that hides the class attribute, so the class name makes the intended shared update clear. @staticmethod defines a method that receives no automatic self argument.
The names in the trace use the Java spelling; total_items is the corresponding Python class variable. A dash means that the object has not yet been initialized.
| Event | First object's label | Second object's label | Shared totalItems | Output |
|---|---|---|---|---|
| Class counter initialized | — | — | 0 | — |
| First label assigned | Camera | — | 0 | — |
| First constructor increments counter | Camera | — | 1 | — |
| Second label assigned | Camera | Tripod | 1 | — |
| Second constructor increments counter | Camera | Tripod | 2 | — |
| First label printed | Camera | Tripod | 2 | Camera |
| Shared count printed | Camera | Tripod | 2 | 2 |
Use an instance variable when the value describes one object. Making label static would mean that all items shared one label, so assigning a new label could affect what every item appears to be called.
Use a class variable when the value genuinely belongs to the group. Here, the count represents all items created, not the condition of any one item.
Use an instance method when the result depends on a particular object's state. Use a static method when no receiving object is needed. A static method can work with an object supplied explicitly as a parameter, but it has no implicit current object.
A parameter or local variable has a narrower scope than a field or attribute: it is available within its method or function call rather than being stored as part of the class or object state.
Terms to use: static variables, non-static variables, static methods, non-static methods, instance variables, class variables, usage, scope.
B3.1.4
DEFINING CLASSES AND CREATING OBJECTS
Constructing a class and its objects requires a class definition, an initialization process and statements that create particular instances. The class describes the structure; creating an object gives that structure its own state.
A constructor is an initialization routine used when creating an object to establish its initial state. It can accept arguments so that different objects begin with different attribute values.
For a simplified LoanItem, the caller supplies a label and the class sets availability to true. Creating “Camera” and “Tripod” therefore produces two available objects with different labels.
In Java, a constructor has the same name as its class and no return type. The new expression creates an instance and invokes the matching constructor.
In Python, calling the class creates an instance, and __init__ initializes it. Strictly, __init__ initializes an already-created object rather than allocating it; it is the initialization method used in this example.
1 public class LoanItem {
2 public String label;
3 public boolean available;
4 public LoanItem(String label) {
5 this.label = label;
6 this.available = true;
7 }
8 public static void main(String[] args) {
9 LoanItem first = new LoanItem("Camera");
10 LoanItem second = new LoanItem("Tripod");
11 first.available = false;
12 System.out.println(first.label);
13 System.out.println(second.label);
14 }
15 }
1 class LoanItem:
2 def __init__(self, label):
3 self.label = label
4 self.available = True
5 first = LoanItem("Camera")
6 second = LoanItem("Tripod")
7 first.available = False
8 print(first.label)
9 print(second.label)
In Java, this refers to the current object. In Python, self is the conventional name for the instance parameter. Both distinguish the attribute belonging to the object from the parameter supplying its initial value.
first. Repeating the process for “Tripod” creates another object, not a second copy of the class definition.
Boolean values below are written as true and false independently of the language's capitalization.
| Event | First label | First availability | Second label | Second availability | Output |
|---|---|---|---|---|---|
| First object's label initialized | Camera | — | — | — | — |
| First object's availability initialized | Camera | true | — | — | — |
| Second object's label initialized | Camera | true | Tripod | — | — |
| Second object's availability initialized | Camera | true | Tripod | true | — |
| First object's availability changed | Camera | false | Tripod | true | — |
| First label printed | Camera | false | Tripod | true | Camera |
| Second label printed | Camera | false | Tripod | true | Tripod |
The constructor establishes a starting condition; it does not prevent later changes. Changing the first object's availability leaves the second object's availability unchanged because these are instance attributes.
The variables first and second hold references to the objects. Declaring a Java reference variable alone does not create an object; the object is created by the new expression. Similarly, the Python class call creates the instance that is then assigned to a name.
Terms to use: define classes, instantiate objects, constructors, initializing an object's state, initial values, attributes.
B3.1.5
ENCAPSULATION AND CONTROLLED ACCESS
Explain encapsulation by showing how a class controls changes to its state, then apply it by making internal data inaccessible through ordinary direct access and providing suitable public operations.
Encapsulation combines state and the operations on that state within a class while controlling access to its members.
Information hiding conceals internal representation and implementation decisions behind an accessible interface. Other code should depend on what an operation promises to do, rather than on how the class stores its data.
The ideas work together. A LoanItem contains its availability state and borrowing behaviour; outside code requests a loan through borrow() rather than assigning availability directly.
borrow() and isAvailable(), but the availability state remains inside the class. This ensures that an ordinary borrowing request goes through the class's rule checks.
| Access choice | Java | Python |
|---|---|---|
| Public interface | A public member is accessible from other code wherever the class is accessible. | Ordinary method names form the public interface by convention. |
| Internal state | A private field can be accessed directly only within its declaring class. | A leading underscore marks a name as non-public by convention; a double leading underscore triggers name mangling. |
| Strength of restriction | The language enforces private access restrictions. | Naming conventions and name mangling discourage accidental access but do not provide Java-style enforced privacy. |
Python's __available is name-mangled to reduce accidental access and naming collisions. It is not a security barrier against code deliberately inspecting or modifying the object.
The item begins available. A successful borrowing operation changes availability to false. A second attempt returns false without changing the state.
1 public class LoanItem {
2 private boolean available = true;
3 public boolean isAvailable() {
4 return available;
5 }
6 public boolean borrow() {
7 if (!available) {
8 return false;
9 }
10 available = false;
11 return true;
12 }
13 public static void main(String[] args) {
14 LoanItem item = new LoanItem();
15 if (item.borrow()) {
16 System.out.println("Loan accepted");
17 }
18 if (!item.borrow()) {
19 System.out.println("Loan refused");
20 }
21 }
22 }
1 class LoanItem:
2 def __init__(self):
3 self.__available = True
4 def is_available(self):
5 return self.__available
6 def borrow(self):
7 if not self.__available:
8 return False
9 self.__available = False
10 return True
11 item = LoanItem()
12 if item.borrow():
13 print("Loan accepted")
14 if not item.borrow():
15 print("Loan refused")
The trace uses available for the internal state in both versions. The returned result belongs to each call; it is not an additional stored attribute.
| Event | Internal availability | Result of borrow call | Output |
|---|---|---|---|
| Item initialized | true | — | — |
| First call changes availability | false | — | — |
| First call returns | false | true | — |
| Success message printed | false | — | Loan accepted |
| Second call returns without changing state | false | false | — |
| Refusal message printed | false | — | Loan refused |
If availability were freely writable, outside code could mark a borrowed item as available without following the intended return process. Restricting direct access funnels changes through operations that can check conditions and preserve valid state.
The public availability method is a getter: it reports a value without changing it. A setter is a method that changes a stored value. Providing a setter for every attribute is not automatically good encapsulation; an unrestricted availability setter would bypass the borrowing rule just as direct assignment would.
A controlled operation such as borrow() expresses the permitted action and enforces its conditions. This protects the integrity of the state and reduces accidental or unauthorized modification through the intended interface. It does not replace wider security measures or make an object immune to every form of interference.
Information hiding also supports maintenance. The internal representation can change while the public operations retain their promised behaviour, reducing the changes required in code that uses the class.
Terms to use: encapsulation, information hiding, access modifiers, private, public, class members, integrity, security, object's state.