Labs ICT
โญ Pro Login

Attributes & Operations

Defining what objects know (attributes) and what they do (operations).

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;
  }
}

๐Ÿงช Quick Quiz

What are attributes in a class?