Skip to main content

Order total and subtotal() redesign

Short answer

The original Order.total() loops over OrderLines, calling getArticle().getPrice() and getQuantity() per line, causing 3n messages and violating Law of Demeter. Adding subtotal() to OrderLine lets it compute price*quantity locally, reducing Order to n messages (subtotal) plus one getPrice per line, cutting messages from 3n to 2n, reducing coupling, and enabling caching.

Your manager reviews your design and codes of a sub-module that you have prepared, as depicted in the below figure. She suggests you to introduce subtotal( ) somewhere in your model thinking about the performance of the system. [Figure: class Order with method total(), with a note attached: "for all my OrderLines ol, tot = tot + ol.getArticle().getPrice() * ol.getQuantity()"; Order is linked to class OrderLine with methods getQuantity() and getArticle(); OrderLine is linked to class Article with method getPrice().] Modify your implementation and justify how does this update provides you better performance.

Present design and its problem

Order.total() loops over all its OrderLines. For each line it calls ol.getArticle(), then article.getPrice(), and ol.getQuantity(), and then multiplies:

 for each ol in orderLines:
     tot = tot + ol.getArticle().getPrice() * ol.getQuantity()

For n lines this makes 3n messages from Order. Order also has to know about Article: it depends on two other classes and reaches through OrderLine to Article, which violates the Law of Demeter. If the objects are remote or loaded from a database, each call may be a network round trip or a query.

Modified design: add subtotal() to OrderLine

OrderLine already knows its quantity and its article, so by the Information Expert principle it should compute its own subtotal.

 +---------+ 1   * +-----------+ *   1 +---------+
 | Order   |-------| OrderLine |-------| Article |
 |---------|       |-----------|       |---------|
 | total() |       | getQuantity()     | getPrice()
 +---------+       | getArticle()      +---------+
                   | subtotal()  <- new
                   +-----------+
class OrderLine {
    private int quantity;
    private Article article;
    public double subtotal() {              // new method
        return article.getPrice() * quantity;
    }
}
class Order {
    private List<OrderLine> lines = new ArrayList<>();
    public double total() {
        double tot = 0;
        for (OrderLine ol : lines)
            tot += ol.subtotal();           // one message per line
        return tot;
    }
}

Why performance improves

  1. Fewer messages: Order sends n messages (subtotal) instead of 3n. The quantity is now read directly inside OrderLine, and only one message to Article (getPrice) remains per line, so the total falls from 3n to 2n messages.
  2. Fewer round trips in a distributed or persistent system: Order makes one call per line instead of three, so there is less network and database traffic and less object loading.
  3. Lower coupling: Order no longer depends on Article; it needs to know only OrderLine. A change in the price calculation (discount, tax) is made only in subtotal().
  4. Easier caching and optimisation: OrderLine can cache its subtotal, and Order can cache the total until a line changes. Each class manages its own data.
  5. Reuse: the subtotal can be used by invoices and reports without repeating the formula.

In a single-process program the saving is small. The real gain is in distributed or database-backed systems, together with better cohesion and maintainability.

✓ Answer checked by Claude Sonnet 5.5

All Object Oriented Analysis and Design chapter 3 questions →