Attributes โ What Objects Know
Attributes are the properties or data that describe an object. They represent the state of an object at any given moment. When choosing attributes, ask: "What information does this object need to do its job?"
Attributes should be meaningful to the class and help distinguish one instance from another. A Student object needs a name and ID, but probably doesn't need a blood type (unless you're building a medical system).
class Student {
// Identity attributes โ distinguish one student from another
studentId; // unique identifier
name; // full name
// Descriptive attributes โ describe the student's current state
email; // contact info
enrollmentDate; // when they started
gpa; // academic performance
status; // active, graduated, suspended
// Derived attributes โ calculated from other attributes
get isHonorRoll() {
return this.gpa >= 3.5;
}
get yearsEnrolled() {
const now = new Date();
const enrolled = new Date(this.enrollmentDate);
return (now - enrolled) / (365.25 * 24 * 60 * 60 * 1000);
}
}
const alice = new Student();
alice.studentId = "STU-2024-001";
alice.name = "Alice Johnson";
alice.email = "alice@university.edu";
alice.enrollmentDate = "2022-09-01";
alice.gpa = 3.8;
alice.status = "active";
console.log(alice.isHonorRoll); // true
console.log(alice.yearsEnrolled.toFixed(1)); // 1.8 years
Choosing the Right Attributes
The key question is: "What information does the system need to track?" This depends entirely on the problem domain, not on implementation details.
Domain: Restaurant Ordering System
โโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Class โ Appropriate Attributes โ
โโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ Menu โ name, categories[], taxRate โ
โ MenuItem โ name, description, price, category, โ
โ โ isAvailable, allergens[] โ
โ Order โ orderId, items[], status, totalAmount, โ
โ โ createdAt, customerInfo โ
โ Customer โ name, phone, email, orderHistory[] โ
โ Table โ tableNumber, capacity, isOccupied, โ
โ โ currentOrderId โ
โโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Notice: We don't track MenuItem.preparationTime here
unless the system actually needs it for scheduling.
Operations โ What Objects Do
Operations (also called methods) define the behavior of an object โ what it can do. They represent actions that change the object's state or provide information about it. Operations should be meaningful actions, not just getters and setters.
class ShoppingCart {
#items = [];
// Operation: modify state
addItem(product, quantity = 1) {
const existing = this.#items.find(i => i.product.id === product.id);
if (existing) {
existing.quantity += quantity;
} else {
this.#items.push({ product, quantity });
}
return this;
}
// Operation: modify state
removeItem(productId) {
this.#items = this.#items.filter(i => i.product.id !== productId);
return this;
}
// Operation: query state
getTotal() {
return this.#items.reduce(
(sum, item) => sum + item.product.price * item.quantity, 0
);
}
// Operation: query state
getItemCount() {
return this.#items.reduce((sum, item) => sum + item.quantity, 0);
}
// Operation: business logic
applyDiscount(code) {
const discount = DiscountService.validate(code);
if (discount) {
return this.getTotal() * (1 - discount.percentage);
}
throw new Error("Invalid discount code");
}
// Operation: transition state
checkout() {
if (this.#items.length === 0) {
throw new Error("Cart is empty");
}
const order = new Order(this.#items);
this.#items = [];
return order;
}
}
Types of Operations
Operations generally fall into several categories:
1. State-Changing Operations (Mutators)
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Modify the object's internal state.
account.deposit(100)
cart.addItem(product)
order.setStatus("shipped")
2. State-Querying Operations (Accessors)
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Return information about the object's state.
account.getBalance()
cart.getTotal()
order.getStatus()
3. Business Logic Operations
โโโโโโโโโโโโโโโโโโโโโโโโโ
Implement domain-specific rules.
order.calculateShipping()
employee.calculateOvertime()
loan.calculateInterest()
4. Lifecycle Operations
โโโโโโโโโโโโโโโโโโโโ
Manage the object's creation and destruction.
new Student("Alice")
connection.close()
timer.start() / timer.stop()
Putting It Together โ A Complete Example
class Course {
// Attributes
#courseId;
#title;
#instructor;
#maxStudents;
#enrolledStudents = [];
#schedule;
#status; // draft, published, active, completed
constructor(courseId, title, instructor, maxStudents, schedule) {
this.#courseId = courseId;
this.#title = title;
this.#instructor = instructor;
this.#maxStudents = maxStudents;
this.#schedule = schedule;
this.#status = "draft";
}
// State-changing operation
enroll(student) {
if (this.#status !== "published") {
throw new Error("Course not available for enrollment");
}
if (this.#enrolledStudents.length >= this.#maxStudents) {
throw new Error("Course is full");
}
if (this.#enrolledStudents.includes(student)) {
throw new Error("Student already enrolled");
}
this.#enrolledStudents.push(student);
}
// State-changing operation
drop(student) {
this.#enrolledStudents = this.#enrolledStudents.filter(
s => s !== student
);
}
// State-querying operation
getEnrollmentCount() {
return this.#enrolledStudents.length;
}
// State-querying operation
hasAvailableSeats() {
return this.#enrolledStudents.length < this.#maxStudents;
}
// Business logic operation
publish() {
if (this.#status !== "draft") {
throw new Error("Only draft courses can be published");
}
this.#status = "published";
}
// Derived attribute
get enrollmentPercentage() {
return (this.#enrolledStudents.length / this.#maxStudents) * 100;
}
}