Construct Classes & Instantiates Objects
Defining Classes and Creating Objects
Classes are blueprints for objects: they define the attributes (data) and methods (behaviour) that each instance will have.
Constructors are special methods that initialise an object’s state when it is created, setting its attributes to meaningful default or provided values.
Defining a Class: Core Steps
- State the purpose: Write one sentence that captures the class’s single responsibility.
- Name it well: Use a clear, singular noun (e.g.
Booking). -
Identify attributes:
List key data as
name: Type, choose visibility (usually-private), note defaults and constraints (e.g.seats ≥ 0).- Python (convention): public
self.name; protectedself._fuel_level; privateself.__pin(name-mangled). - Java: public
public double price;protectedprotected String model;privateprivate int seats = 0;
- Python (convention): public
-
Identify attributes:
List key data as
name: Type, choose visibility (usually-private), note defaults and constraints (e.g.seats ≥ 0).- Python (convention): public
self.name; protectedself._fuel_level; privateself.__pin(name-mangled). - Java: public
public double price;protectedprotected String model;privateprivate int seats = 0;
- Python (convention): public
- Identify behaviour: List methods as
name(params): ReturnType; describe each method’s effect in a short phrase. - Design construction: Decide required vs optional parameters; validate inputs in the constructor.
-
Set visibility & access:
Expose only what clients need; keep internal state encapsulated.
-
Python (convention):
public
def start(self):; protecteddef _validate(self):; private (name-mangled)def __recalc(self):. -
Java:
public
public void start() { }; protectedprotected void validate() { }; privateprivate void recalc() { }.
-
Python (convention):
public
- Relate to other classes: Specify HAS-A (aggregation/composition) or IS-A (inheritance) and multiplicities (e.g.
1,0..*). - Sketch the UML: Draw name | attributes | operations with visibility symbols (
+,-,#) as a final check.
Instantiating Objects: Core Steps
- Pick the right class: Choose the type that models the thing you need for this task.
- Choose a constructor: Gather valid values for all required parameters; note any optional ones.
- Create the instance: Instantiate and assign to a clearly named variable (so its role is obvious).
- Validate state: Ensure invariants hold after construction. These are your always-true rules (e.g.
startTimeis never afterendTime); handle any errors early. - Configure optional state: Call setters or builder methods to finish setup without breaking invariants.
- Use the object: Use behaviours (methods) to achieve the required outcome; avoid exposing internals.
- Store or release: If you’ll need it again, add it to a container (e.g. a list that is responsible for keeping it). If not, let it go out of scope (don’t keep any references) so free/destroy it.
- Manage resources: For objects (less commonly) holding files/network handles, use Python
withor Java try-with-resources to close them reliably.
Example: Defining a Class and Instantiating Objects
Define a Car with constructor, methods, and getters/setters; then create two distinct objects.
class Car:
def __init__(self, make: str, model: str, fuel_level: float):
# Private attributes, marked as __
self.__make = make
self.__model = model
self.__fuel_level = fuel_level
# Public behaviour
def start_engine(self) -> None:
print(f"{self.make} {self.model} engine started.")
def drive(self, distance: float) -> None:
# consume 0.1 litres per km (example rate)
new_level = self.__fuel_level - (distance * 0.1)
self.fuel_level = new_level # go through the setter for validation
print(f"Drove {distance} km. Remaining fuel: {self.fuel_level:.1f} litres.")
def get_fuel_level(self) -> float:
# Note: The use of -> in Python is purely for info; it does not enforce anything
# Getter: return the current fuel level
return self.__fuel_level
def set_fuel_level(self, new_level: float):
# Setter: update the fuel level to a new value
if new_level >= 0:
self.__fuel_level = new_level
else:
print("Error: Fuel level cannot be negative.")
# Instantiate two Car objects
car1 = Car("Toyota", "Corolla", 50.0)
car2 = Car("Honda", "Civic", 45.0)
# Use methods and getters/setters
car1.start_engine()
car1.drive(100)
print("Car1 fuel:", car1.get_fuel_level())
car2.set_fuel_level(40.0)
print("Car2 fuel after refill:", car2.get_fuel_level())
public class Car {
private String make; // instance field
private String model;
private double fuelLevel;
public Car(String make, String model, double fuelLevel) {
// Constructor: initialise instance fields
this.make = make;
this.model = model;
this.fuelLevel = fuelLevel;
}
public void startEngine() {
// Method to start the engine
System.out.println(make + " " + model + " engine started.");
}
public void drive(double distance) {
// Method to drive the car and consume fuel
fuelLevel -= distance * 0.1;
System.out.printf("Drove %.1f km. Remaining fuel: %.1f litres.%n", distance, fuelLevel);
}
// Getter for fuelLevel
public double getFuelLevel() {
return fuelLevel;
}
// Setter for fuelLevel
public void setFuelLevel(double newLevel) {
if (newLevel >= 0) {
this.fuelLevel = newLevel;
} else {
System.out.println("Error: Fuel level cannot be negative.");
}
}
public static void main(String[] args) {
Car car1 = new Car("Toyota", "Corolla", 50.0);
Car car2 = new Car("Honda", "Civic", 45.0);
car1.startEngine();
car1.drive(100);
System.out.println("Car1 fuel: " + car1.getFuelLevel());
car2.setFuelLevel(40.0);
System.out.println("Car2 fuel after refill: " + car2.getFuelLevel());
}
}
Key Takeaways
- Define a class to bundle related attributes and methods.
- Use a constructor (
__init__in Python, same-name method in Java) to initialise instance variables. - Instantiate objects by calling the class name with required arguments.
- Each object maintains its own state, independent of other instances.