COP4331: From UML Diagrams to Code

This document describes how to do a quick implementation of classes in Java starting from UML diagrams. We will use an online auction application as an example.

The problem is described here.

Prototype implementations for Online Auction classes are posted here (javadoc html)
This code is incomplete and lacks proper error checking.
It only illustrates the implementation steps described below.


The diagrams have been built using use cases and CRC cards.

The class diagram describes the conceptual model:

(violet)

A more detailed class diagram would list all attributes and methods. Note that attributes are of primitive (or simple) types, such as number types, String, Date. Object references typically implement associations, aggregations, compositions.

Here is what we do with the class diagrams:

Note that we do not discuss the inheritance relationship here.

Considering this, the ActiveList class would look like:
    public class ActiveList {
        /** list of AuctionListing objects
         */
        private ArrayList<AuctionListing> auctListings;    

        // add methods and attributes from the class diagram
    };
and initial code the AuctionListing class is:
    public class AuctionListing {

        // object references from aggregations and associations:
        private Item item;

        private BidHistory bidHist;

        private Seller seller;

        private Auctioneer auctioneer;

        // object attributes:
        private Date deadline;              // auction deadline

        private double startPrice;          // the auction starting price
    };



From the sequence diagrams we determine the main course of action for methods, as described in the use cases.
Consider the "List Item" sequence diagram:


(violet)


The sequence diagram shows the time order for messages sent between objects while performing a use case scenario.


In UML, the fact that "an object A sends a message m() to another object B", maps in an object-oriented programming language (e.g. Java) to "object B implements method m() and object A invokes method m() on object B". The UML notation for a message (arrow) does not show that the target object may return a value. It is assumed that it terminates processing the message at the end of the activation block.

The basic rules for mapping a sequence diagram to code are:
  • for each object, an "incoming message" maps to a method that must be implemented by the object receiving the message.
  • for a complete application implementation, all objects in all sequence diagrams must be considered according to these rules.
  • the message name, return value and parameter list (signature) map to the method signature in the code implementation.
  • the code implementation still must be fully defined even if the sequence diagram is high-level, or a message signature does not specify return value or parameters.
  • the method implementation consists in part of the messages the object sends during the current message activation box. If object A sends a message m(...) to another object B, then the mapping to A's code is a call B.m(...).
  • the message order from the sequence diagram must be preserved in the method code.
  • sequence diagrams for alternate scenarios (e.g. success vs. failure scenario) may include the same message sent to a particular object, but showing a different sequence. The code from alternate sequences must be merged during the implementation using if-else branches. (see the listItem() method below)
    If the code gets too complicated, try breaking it into multiple (helper) methods.
  • if object A sends a message to object B, then object A must have a reference to the B object (A calls B.someMethod()). The reference to B object may be an instance variable of the A object, or a local/temporary variable obtained indirectly (e.g. through accessors applied to third-party objects).
  • consider adding such reference instance variables as appropriate.
  • methods implementing messages between objects should have "package" or "public" visibility. Helper methods are "private".
NOTE: always keep applying the concepts and methodologies from Chapters 2 & 3. Think about encapsulation, side effects, the Law of Demeter.


In this above figure, the Seller object sends a listItem() message to the :AuctionSystem object. Thus, class AuctionSystem must implement method listItem(). The AuctionSystem.listItem() method simply invokes the listItem() method on the ActiveList object.

The ActiveList.listItem() method is a bit more complex:
    public class ActiveList {
        .......
        public void listItem(Item it, Date deadline, double price) {
            // create new AuctionListing (call constructor):
            AuctionListing al = new AuctionListing(it, deadline, price);

            // create auctioneer for this listing:
            Auctioneer au = new Auctioneer(al);

            // implementation choice: validateListing() returns true/false
            // if validation succeeds, add to ActiveList:
            if (au.validateListing()) {

                // add the new auction listing:
                this.auctListings.add(al);

                // schedule auction completion:
                au.scheduleCompletion();
            }
            else {
                // indicate error to user
                // ... omitted ...
            }
        }
        .......
    }

Furthermore, the Auctioneer class must implement the validateListing() and scheduleCompletion() methods.


Prototype implementation for some of the classes are posted here.


For questions, contact the instructor.


Last modified: Wed Sep 14 12:08:11 EDT 2005