Assignment Chef icon Assignment Chef
All English tutorials

Programming lesson

Mastering OOP and Data Structures: Build a Store Inventory System Like AI Assistants at McGill

Learn how to design classes, use inheritance, and implement custom linked lists by building a store inventory system inspired by a real ECSE250 assignment. Perfect for practicing OOP and data structures with Java.

ECSE250 assignment 1 Java OOP tutorial store inventory system Java abstract classes Java inheritance Java example custom linked list Java data structures practice McGill programming assignment AI assistant programming object-oriented design Java equals method linked list implementation Java polymorphism class hierarchy design Java assignment help coding practice for students

Introduction: Why This Assignment Matters

In ECSE250 Assignment 1, you are tasked with creating an AI assistant for a new convenience store at McGill's Trottier building. This assignment is a fantastic opportunity to practice object-oriented design (OOD) and data structures—skills that are essential for any software developer. Just as AI-powered apps like ChatGPT or recommendation systems rely on well-structured code to manage data efficiently, your store assistant will need robust classes and a custom data structure to handle inventory.

This tutorial will guide you through the key concepts without giving away the exact solution. By the end, you'll understand how to design abstract classes, use inheritance, and implement a linked list from scratch—all while keeping your code clean and efficient.

Step 1: Understanding the Class Hierarchy

The assignment requires several classes organized in a package named assignment1.items. The base class is StoreItem, which represents any product in the store. It has private fields for price (double) and happinessIndex (int). The constructor should throw an IllegalArgumentException if either value is negative—a common practice to ensure data integrity.

Next, Drink extends StoreItem and adds fields like numOfBottles (protected int) and buzzy (private boolean). Notice that Drink overrides getHappinessIndex() to add a boost if the drink is buzzy. This is a classic example of polymorphism: the same method behaves differently based on the object type.

You'll also create concrete classes like FizzWiz, SnoozeJuice, and Snack that extend Drink or StoreItem. Each adds its own unique properties. For instance, Snack might have a nutritionRating field. This hierarchy reduces code duplication—a core benefit of OOP.

Step 2: Writing the Abstract Classes

Let's start with StoreItem. It should be abstract, meaning you cannot instantiate it directly. Here's a skeleton:

package assignment1.items;

public abstract class StoreItem {
    private double price;
    private int happinessIndex;

    public StoreItem(double price, int happinessIndex) {
        if (price < 0 || happinessIndex < 0) {
            throw new IllegalArgumentException("Price and happiness index must be non-negative.");
        }
        this.price = price;
        this.happinessIndex = happinessIndex;
    }

    public final double getPrice() { return price; }

    public int getHappinessIndex() { return happinessIndex; }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null || getClass() != obj.getClass()) return false;
        StoreItem other = (StoreItem) obj;
        return Math.abs(this.price - other.price) < 0.001 && this.happinessIndex == other.happinessIndex;
    }
}

Notice the use of final on getPrice()—this prevents subclasses from overriding it. The equals() method uses a tolerance for double comparison (difference < 0.001) to avoid floating-point issues. This is a common gotcha in Java.

Now, the Drink class:

package assignment1.items;

public abstract class Drink extends StoreItem {
    public static final int MAX_PACK_SIZE = 6;
    public static final int BUZZY_HAPPINESS_BOOST = 1;
    protected int numOfBottles;
    private boolean buzzy;

    public Drink(double price, int happinessIndex, int numOfBottles, boolean buzzy) {
        super(price, happinessIndex);
        this.numOfBottles = numOfBottles;
        this.buzzy = buzzy;
    }

    public int getNumOfBottles() { return numOfBottles; }

    @Override
    public int getHappinessIndex() {
        return buzzy ? super.getHappinessIndex() + BUZZY_HAPPINESS_BOOST : super.getHappinessIndex();
    }

    @Override
    public boolean equals(Object obj) {
        if (!super.equals(obj)) return false;
        Drink other = (Drink) obj;
        return this.buzzy == other.buzzy;
    }

    public boolean combine(Drink other) {
        // Implementation depends on assignment specifics
    }
}

Here, super.equals(obj) is called to reuse the parent's logic, then we add the buzzy check. This avoids rewriting the price and happiness comparison.

Step 3: Implementing a Custom Linked List (ItemList)

The assignment forbids using ArrayList or LinkedList from Java's standard library. Instead, you must create your own ItemList class. This is excellent practice for understanding how linked lists work under the hood.

A linked list consists of nodes, each storing a reference to the next node. You'll need a private inner class Node with fields for the item and next node. The ItemList should support methods like add, remove, get, and size. Consider using a dummy head node to simplify edge cases.

For example, the add method might insert at the end:

public void add(StoreItem item) {
    Node newNode = new Node(item);
    if (head == null) {
        head = newNode;
    } else {
        Node current = head;
        while (current.next != null) {
            current = current.next;
        }
        current.next = newNode;
    }
    size++;
}

Remember to handle cases like removing an item that matches by equals()—but be careful not to create shallow copies unless specified.

Step 4: The Store Class and AI Assistant Logic

The Store class ties everything together. It should have an ItemList field representing inventory. Methods like addItem, removeItem, and findItem will delegate to the list. The AI assistant aspect might involve suggesting items based on happiness index or price, or handling purchases.

Think of it like a recommendation system: given a customer's mood (e.g., they want a buzzy drink), the assistant can search the inventory for matching items. This is similar to how Spotify suggests songs based on your listening history—both rely on efficient data retrieval.

Step 5: Testing and Debugging

The assignment includes tester files that will run automatically when you submit to Ed. To avoid surprises, test your code locally. Write a simple main method in a separate class (not submitted) to create objects and call methods. Use toString() methods to print debug info.

Remember: do not submit .class files or tester files. Only the required .java files. And ensure your code compiles on Ed—any compilation error results in a zero.

Conclusion: Why This Assignment Prepares You for Real-World Development

Building a store inventory system from scratch teaches you to think about class design, inheritance, and data structures. These are the same skills used in developing AI assistants, e-commerce platforms, and even video game inventories. By mastering OOP and linked lists, you'll be ready for more advanced topics like design patterns and algorithms.

So, take your time, draw that UML diagram, and ask yourself why each modifier is used. Good luck!