Assignment Chef icon Assignment Chef
All English tutorials

Programming lesson

Building a Retail Store Application in Java: Objects That Contain Objects

Learn how to implement a RetailStoreApplication in Java using composition—objects that contain other objects. This tutorial covers RetailItem, CashRegister, and a driver class with real-world examples.

Java composition objects that contain objects RetailStoreApplication ICS 141 assignment Java retail program CashRegister class RetailItem class Java OOP tutorial inventory management Java Java getUnits method Java changePrice method Java equals method override Java driver class Java programming assignment help object-oriented programming example Java retail store simulation

Introduction: Why Composition Matters in Java

In object-oriented programming, one of the most powerful concepts is composition—creating objects that contain other objects. Think of it like building a gaming PC: you have a CPU, GPU, RAM, and each component is an object. The PC itself is an object that contains these parts. In Java, this pattern appears everywhere, from GUI applications to retail systems. Today, we'll build a RetailStoreApplication that models a real store, where a CashRegister contains a RetailItem object. This is exactly the kind of project you might encounter in ICS 141 assignments, and it's a great way to master composition.

Let's dive into the three classes: RetailItem, CashRegister, and RetailStoreDriver. By the end, you'll have a working application that tracks inventory, processes sales, and calculates totals—just like a real point-of-sale system.

Class 1: RetailItem – The Building Block

The RetailItem class holds data about a single item in the store. It has three instance variables: description (String), unitsOnHand (int), and price (double). These represent what the item is, how many are in stock, and how much it costs.

Constructor and Getters

The constructor takes two arguments—description and price—and sets unitsOnHand to zero. This is common when you first add an item to the system: you don't know the quantity yet. Later, you can add units using addUnits(). Here's the constructor:

public RetailItem(String description, double price) {
    this.description = description;
    this.price = price;
    this.unitsOnHand = 0;
}

Getters are straightforward: getDescription(), getUnitsOnHand(), getPrice(). They return the corresponding values.

Core Business Methods

The addUnits(int number) method adds a positive number to unitsOnHand. It's like receiving a shipment of new items. The getUnits(int number) method simulates selling items: it checks if enough stock exists. If yes, it subtracts the quantity and returns true; otherwise, it returns false without modifying stock. This is crucial for inventory accuracy.

The changePrice(double amount) method adjusts the price. If the new price would be zero or negative, it prints an error and does nothing. This prevents absurd prices like -$5.00.

Finally, totalValue() calculates the inventory value: unitsOnHand * price. And equals(Object obj) checks if two items have the same description and price—useful for comparing products.

Class 2: CashRegister – The Composition in Action

Now comes the exciting part: the CashRegister class contains a RetailItem object. This is composition at work. The register also has a clerk (String) and a quantity (int) representing how many units are being sold.

Constructor and Getters

The constructor takes the clerk's name, a RetailItem object, and the quantity to purchase. It assumes the quantity is valid (less than or equal to units on hand). It calls item.getUnits(quantity) to reduce the item's stock. This is a perfect example of an object using another object's method to modify its state.

Getters: getClerk(), getItem(), getQuantity().

Sales Calculations

getSubTotal() returns quantity * item.getPrice(). getTax(double rate) returns subtotal * rate. getTotal(double rate) returns subtotal + tax. These methods encapsulate the math, making the driver class clean.

Modifying Quantity During a Sale

The modifyQuantity(int number) method adjusts the quantity being sold. If you add 2 more items, it subtracts 2 from the item's units on hand (by calling item.getUnits(2)). If you reduce by 2, it adds 2 back (by calling item.addUnits(2)). This keeps inventory consistent—a real-world scenario when a customer changes their mind at the register.

The getItemAvailability() method simply returns item.getUnitsOnHand(), giving the current stock after any modifications.

Class 3: RetailStoreDriver – Putting It All Together

The driver class contains the main method. It creates two RetailItem objects (e.g., a jacket and a phone case), prints their details, and tests all methods on one item. Then it creates a CashRegister object, processes a sale, and displays the receipt.

Here's a snippet of the driver:

public class RetailStoreDriver {
    public static void main(String[] args) {
        RetailItem jacket = new RetailItem("Jacket", 59.54);
        jacket.addUnits(12);
        System.out.println(jacket);
        
        CashRegister register = new CashRegister("Alice", jacket, 2);
        double subtotal = register.getSubTotal();
        double tax = register.getTax(0.04);
        double total = register.getTotal(0.04);
        System.out.println("Subtotal: $" + subtotal);
        System.out.println("Tax: $" + tax);
        System.out.println("Total: $" + total);
        
        System.out.println("\nProgram by: Your Name");
    }
}

Notice how the driver never directly manipulates the item's units; it goes through the CashRegister methods. This is good encapsulation.

Testing and Verification

To verify your code, run the driver and check that:

  • Jacket details show description, units, and price separated by tabs.
  • After selling 2 jackets, units on hand drop from 12 to 10.
  • Subtotal = 2 * 59.54 = 119.08, tax = 119.08 * 0.04 = 4.7632, total = 123.8432.
  • If you try to sell more than available, getUnits() returns false and no change occurs.

Test edge cases: change price to a negative amount (should error), add zero units, and compare two identical items with equals().

Real-World Connections: From Retail to AI Apps

Composition isn't just for retail. Consider a popular AI app like a chatbot: the chatbot object contains a language model object, a user profile object, and a conversation history object. Each component is independent but works together. Similarly, in gaming, a player object contains an inventory object, which contains item objects. Understanding composition helps you design scalable systems.

Even in finance, a portfolio object contains multiple stock objects. Each stock has its own price and shares, and the portfolio calculates total value—just like our CashRegister calculates totals from the item's price.

Conclusion: Mastering Composition in Java

By building this RetailStoreApplication, you've learned how to create objects that contain other objects. You've seen encapsulation, method delegation, and real-world validation. This pattern is fundamental to Java and OOP. Whether you're building a store, a game, or an AI tool, composition will be your go-to design technique.

Remember to comment your code, indent consistently, and include your name at the top. Good luck with your ICS 141 assignment!