Chapter 16

System Design


Chapter Goals

Software Life Cycle

Encompasses all activities from initial analysis until obsolescence

Development Process

The Waterfall Model

The Spiral Model

Describes an iterative process in which design and implementation are repeated


Extreme Programming

Development methodology that strives for simplicity by removing formal structure and focusing on best practices

Object-Oriented Design

Discovering Classes

CRC Card

A CRC Card

Relationships Between Classes

"Is-a" / "Has-a" /"Uses

Example:
class Car extends Vehicle       //inheritance "is-a"
{
   ...
   private Tire[] tires;         //instance variable "has-a"
}

Association and Dependency

UML Notation for Inheritance and Association

UML Relationship Symbols

Relationship
Symbol
Line Style
Arrow tip

Inheritance

Solid

Closed

Realization

Dotted

Closed

Association

Solid

Open

Dependency

Dotted

Open

s

Five-Part Development Process

  1. Gather requirements
  2. Use CRC cards to find classes, responsibilities, and collaborators
  3. Use UML diagrams to record class relationships
  4. Use javadoc to document method behavior
  5. Implement your program

Example: Printing an Invoice - Requirements


INVOICE
Sam's Small Appliances        
100 Main Street        
Anytown, CA 98765        
         
Description   Price
Qty
Total
Toaster   29.95
3
89.85
Hair dryer   24.95
1
24.95
Car vacuum   19.99
2
39.98
         
Amount Due:   $154.78        

Example: Printing an Invoice - CRC Cards

CRC Cards for Printing Invoice

Invoice
format the invoice
Address
add a product and quantity Item
  Product
   
   
   
   
   

 

Address
format the address
 
   
   
   
   
   
   
   

 

Product
get description
 
get unit price  
   
   
   
   
   
   

 

Item
format the item
Product
get total price  
   
   
   
   
   
   

Example: Printing an Invoice - UML Diagrams

The relationship between Invoice classes


Example: Printing an Invoice - Method Documentation

Example: Printing an Invoice - Method Documentation


/**
   Describes an invoice for a set of purchased products.
*/
class Invoice
{
   /**
      Adds a charge for a product to this invoice.
      @param aProduct the product that the customer ordered
      @param quantity the quantity of the product
   */
   public void add(Product aProduct, int quantity)
   {
   }

   /**
      Formats the invoice.
      @return the formatted invoice
   */
   public String format()
   {
   }

   /**
      Computes the total amount due.
      @Return the amount due
   */
   public double getAmountDue()
   {
   }
}



/**
   Describes a quantity an article to purchase and its price.
*/
Class Item
{
   /**
      Computes the total cost of this item.
      @Return the total price
   */
   public double getTotalPrice()
   {
   }

   /**
      Formats this item.
      @Return a formatted string of this item
   */
    public String format()
    {
    }
 }

/**
   Describes a product with a description and a price
*/
class Product
{
   /**
      Gets the product description.
      @Return the description
   */
   public String getDescription()
   {
   }

   /**
      Gets the product price.
      @Return the unit price
   */
   public double getPrice()
   {
   }
}



/**
   Describes a mailing address.
*/
Class Address
{
   /**
      Formats the address.
      @Return the address as a string with 3 lines
   */
   public String format()
   {
   }
}

The Class Documentation in the HTML Format

Example: Printing an Invoice - Implementation

File InvoiceTest.java

1import java.util.Vector;
2
3 /**
4   This program tests the invoice classes by printing
5   a sample invoice.
6*/
7public class InvoiceTest
8{  
9   public static void main(String[] args)
10   {  
11      Address samsAddress 
12          = new Address("Sam's Small Appliances",
13            "100 Main Street", "Anytown", "CA", "98765");
14
15      Invoice samsInvoice = new Invoice(samsAddress);
16      samsInvoice.add(new Product("Toaster", 29.95), 3);
17      samsInvoice.add(new Product("Hair dryer", 24.95), 1);
18      samsInvoice.add(new Product("Car vacuum", 19.99), 2);
19
20      System.out.println(samsInvoice.format());           
21   }
22}
23
24
25

File Invoice.java

1import java.util.ArrayList;
2
3 /**
4   Describes an invoice for a set of purchased products.
5*/
6class Invoice
7{  
8   /**
9      Constructs an invoice.
10      @param anAddress the billing address
11   */
12   public Invoice(Address anAddress)
13   {  
14      items = new ArrayList();
15      billingAddress = anAddress;
16   }
17  
18   /**
19      Adds a charge for a product to this invoice.
20      @param aProduct the product that the customer ordered
21      @param quantity the quantity of the product
22   */
23   public void add(Product aProduct, int quantity)
24   {  
25      Item anItem = new Item(aProduct, quantity);
26      items.add(anItem);
27   }
28
29   /**
30      Formats the invoice.
31      @return the formatted invoice
32   */
33   public String format()
34   {  
35      String r =  "                     I N V O I C E\n\n"
36         + billingAddress.format()
37         + "\n\nDescription                   Price  Qty  Total\n";
38      for (int i = 0; i < items.size(); i++)
39      {  
40         Item nextItem = (Item)items.get(i);
41         r = r + nextItem.format() + "\n";
42      }
43
44      r = r + "\nAMOUNT DUE: $" + getAmountDue();
45
46      return r;
47   }
48
49   /**
50      Computes the total amount due.
51      @return the amount due
52   */
53   public double getAmountDue()
54   {  
55      double amountDue = 0;
56      for (int i = 0; i < items.size(); i++)
57      {  
58         Item nextItem = (Item)items.get(i);
59         amountDue = amountDue + nextItem.getTotalPrice();
60      }
61      return amountDue;
62   }
63   
64   private Address billingAddress;
65   private ArrayList items;
66}

File Item.java

1/**
2   Describes a quantity an article to purchase and its price.
3*/
4class Item
5{  
6   /**
7      Constructs an item from the product and quantity
8      @param aProduct the product
9      @param aQuantity the item quantity
10   */
11   public Item(Product aProduct, int aQuantity)
12   {  
13      theProduct = aProduct;
14      quantity = aQuantity;
15   }
16   
17   /**
18      Computes the total cost of this item.
19      @return the total price
20   */
21   public double getTotalPrice()
22   {  
23      return theProduct.getPrice() * quantity;
24   }
25   
26   /**
27      Formats this item.
28      @return a formatted string of this item
29   */
30   public String format()
31   {  
32      final int COLUMN_WIDTH = 30;
33      String description = theProduct.getDescription();
34           
35      String r = description;
36
37      // pad with spaces to fill column
38      
39      int pad = COLUMN_WIDTH - description.length();
40      for (int i = 1; i <= pad; i++)
41         r = r + " ";
42   
43      r = r + theProduct.getPrice()
44         + "   " + quantity 
45         + "   " + getTotalPrice();
46
47      return r;
48   }
49
50   private int quantity;
51   private Product theProduct;
52}

File Product.java

1/**
2   Describes a product with a description and a price
3*/
4class Product
5{  
6   /**
7      Constructs a product from a description and a price.
8      @param aDescription the product description
9      @param aPrice the product price
10   */
11   public Product(String aDescription, double aPrice)
12   {  
13      description = aDescription;
14      price = aPrice;
15   }
16   
17   /**
18      Gets the product description.
19      @return the description
20   */
21   public String getDescription()
22   {  
23      return description;
24   }
25
26   /**
27      Gets the product price.
28      @return the unit price
29   */
30   public double getPrice()
31   {
32      return price;
33   }
34   
35   private String description;
36   private double price;
37}
38

File Address.java

1/**
2   Describes a mailing address.
3*/
4class Address
5{  
6   /**
7      Constructs a mailing address. 
8      @param aName the recipient name
9      @param aStreet the street
10      @param aCity the city
11      @param aState the 2-letter state code
12      @param aZip the ZIP postal code
13   */
14   public Address(String aName, String aStreet,
15      String aCity, String aState, String aZip)
16   {  
17      name = aName;
18      street = aStreet;
19      city = aCity;
20      state = aState;
21      zip = aZip;
22   }   
23
24   /**
25      Formats the address.
26      @return the address as a string with 3 lines
27   */
28   public String format()
29   {  
30      return name + "\n" + street + "\n"
31         + city + ", " + state + " " + zip;
32   }
33   
34   private String name;
35   private String street;
36   private String city;
37   private String state;
38   private String zip;
39}
40

Example: An Automatic Teller Machine - Requirements

User Interface of the Automatic Teller Machine

 

Example: An Automatic Teller Machine - CRC

CRC Cards for Automatic Teller Machine

Keypad
get value entered
 
   
   
   
   
   
   
   

 

Customer
get accounts
 
match number and PIN  
   
   
   
   
   
   

 

Bank
find customer
Customer
read customers  
   
   
   
   
   
   

 

 

ATM
set state
Customer
select customer Bank
select account BankAccount
execute transaction Keypad
   
   
   
   

 

ATM States

  1. START: Enter customer ID
  2. PIN: Enter PIN
  3. ACCOUNT: Select account
  4. TRANSACT: Select transaction

State Diagram for ATM Class

Example: An Automatic Teller Machine - UML Diagram

The Relationships Between the ATM Classes

Example: An Automatic Teller Machine - Method Documentation

ATM Class Method Documentation

public class ATM
{
   /**
      Gets PIN from keypad, finds customer in bank.
      If found sets state to ACCOUNT, else to START.
   */
   public void selectCustomer()
   {
   }


   /**
      Sets current account to checking or savings. Sets
      state to TRANSACT
      @param account one of CHECKING_ACCOUNT or SAVINGS_ACCOUNT
   */
   public void selectAccount(int account)
   {
   }


   /**
      Withdraws amount typed in keypad from current account.
      Sets state to ACCOUNT.
   */
   Public void withdraw()
   {
   }


   /**
      Deposits amount typed in keypad to current account.
      Sets state to ACCOUNT.
   */
   Public void deposit()
   {
   }


   /**
      Sets state and updates display message.
      @param state the next state
   */
   public void setState(int newState)
   {
   }
}

Example: An Automatic Teller Machine - Implementation

File ATMSimulation.java

1import javax.swing.JFrame;
2
3/**
4   A simulation of an automatic teller machine
5*/
6public class ATMSimulation
7{  
8   public static void main(String[] args)
9   {  
10      JFrame frame = new ATM();
11      frame.setTitle("First National Bank of Java");      
12      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
13      frame.pack();
14      frame.show();
15   }
16}
17

File ATM.java

1import java.awt.Container;
2import java.awt.FlowLayout;
3import java.awt.GridLayout;
4import java.awt.event.ActionEvent;
5import java.awt.event.ActionListener;
6import java.io.IOException;
7import javax.swing.JButton;
8import javax.swing.JFrame;
9import javax.swing.JOptionPane;
10import javax.swing.JPanel;
11import javax.swing.JTextArea;
12
13/**
14   A frame displaying the components of an ATM
15*/
16class ATM extends JFrame
17{  
18   /**
19      Constructs the user interface of the ATM application.
20   */
21   public ATM()
22   {  
23      // initialize bank and customers
24
25      theBank = new Bank();
26      try
27      {  
28         theBank.readCustomers("customers.txt");
29      }
30      catch(IOException e)
31      {  
32         JOptionPane.showMessageDialog(null, 
33            "Error opening accounts file.");
34      }
35   
36      // construct components
37
38       pad = new Keypad();
39
40      display = new JTextArea(4, 20);
41      
42      aButton = new JButton("  A  ");
43      aButton.addActionListener(new AButtonListener());
44
45      bButton = new JButton("  B  ");
46      bButton.addActionListener(new BButtonListener());
47
48      cButton = new JButton("  C  ");
49      cButton.addActionListener(new CButtonListener());
50      
51      // add components to content pane
52
53      JPanel buttonPanel = new JPanel();
54      buttonPanel.setLayout(new GridLayout(3, 1));
55      buttonPanel.add(aButton);
56      buttonPanel.add(bButton);
57      buttonPanel.add(cButton);
58      
59      Container contentPane = getContentPane();
60      contentPane.setLayout(new FlowLayout());
61      contentPane.add(pad);
62      contentPane.add(display);
63      contentPane.add(buttonPanel);
64
65      setState(START_STATE);      
66   }
67   
68   /** 
69      Sets the current customer number to the keypad value
70      and sets state to PIN.
71   */
72   public void setCustomerNumber() 
73   {  
74      customerNumber = (int)pad.getValue();
75      setState(PIN_STATE);
76   }
77
78   /** 
79      Gets PIN from keypad, finds customer in bank.
80      If found sets state to ACCOUNT, else to START.
81   */
82   public void selectCustomer()
83   {  
84      int pin = (int)pad.getValue();
85      currentCustomer 
86         = theBank.findCustomer(customerNumber, pin);
87      if (currentCustomer == null) 
88         setState(START_STATE);
89      else 
90         setState(ACCOUNT_STATE);
91   }
92   
93   /** 
94      Sets current account to checking or savings. Sets 
95      state to TRANSACT
96      @param account one of CHECKING_ACCOUNT or SAVINGS_ACCOUNT
97   */
98   public void selectAccount(int account)
99   {
100      if (account == CHECKING_ACCOUNT)
101         currentAccount = currentCustomer.getCheckingAccount();
102      else
103         currentAccount = currentCustomer.getSavingsAccount();
104      setState(TRANSACT_STATE);
105   }
106
107   /** 
108      Withdraws amount typed in keypad from current account. 
109      Sets state to ACCOUNT. 
110   */
111   public void withdraw()
112   {  
113      currentAccount.withdraw(pad.getValue());
114      setState(ACCOUNT_STATE);
115   }
116
117   /** 
118      Deposits amount typed in keypad to current account. 
119      Sets state to ACCOUNT. 
120   */
121   public void deposit()
122   {  
123      currentAccount.deposit(pad.getValue());
124      setState(ACCOUNT_STATE);
125   }
126
127   /** 
128      Sets state and updates display message.
129      @param state the next state
130   */
131   public void setState(int newState)
132   {  
133      state = newState;
134      pad.clear();
135      if (state == START_STATE)
136         display.setText("Enter customer number\nA = OK");
137      else if (state == PIN_STATE)
138         display.setText("Enter PIN\nA = OK");
139      else if (state == ACCOUNT_STATE)
140         display.setText("Select Account\n" 
141           + "A = Checking\nB = Savings\nC = Exit");
142      else if (state == TRANSACT_STATE)
143         display.setText("Balance = " 
144            + currentAccount.getBalance() 
145            + "\nEnter amount and select transaction\n"
146            + "A = Withdraw\nB = Deposit\nC = Cancel");
147   }
148   
149   private class AButtonListener implements ActionListener
150   {  
151      public void actionPerformed(ActionEvent event)
152      {  
153         if (state == START_STATE)
154            setCustomerNumber();
155         else if (state == PIN_STATE)
156            selectCustomer();
157         else if (state == ACCOUNT_STATE)
158            selectAccount(CHECKING_ACCOUNT);
159         else if (state == TRANSACT_STATE)
160            withdraw();
161      }
162   }
163   
164   private class BButtonListener implements ActionListener
165   {  
166      public void actionPerformed(ActionEvent event)
167      {  
168         if (state == ACCOUNT_STATE)
169            selectAccount(SAVINGS_ACCOUNT);
170         else if (state == TRANSACT_STATE)
171            deposit();
172      }
173   }
174
175   private class CButtonListener implements ActionListener
176   {  
177      public void actionPerformed(ActionEvent event)
178      {  
179         if (state == ACCOUNT_STATE)
180            setState(START_STATE);
181         else if (state == TRANSACT_STATE)
182            setState(ACCOUNT_STATE);
183      }
184   }
185
186   private int state;
187   private int customerNumber;
188   private Customer currentCustomer;
189   private BankAccount currentAccount;
190   private Bank theBank;
191   
192   private JButton aButton;
193   private JButton bButton;
194   private JButton cButton;
195   
196   private KeyPad pad;
197   private JTextArea display;
198   
199   private static final int START_STATE = 1;
200   private static final int PIN_STATE = 2;
201   private static final int ACCOUNT_STATE = 3;
202   private static final int TRANSACT_STATE = 4;
203
204   private static final int CHECKING_ACCOUNT = 1;
205   private static final int SAVINGS_ACCOUNT = 2;
206}

File KeyPad.java

1import java.awt.BorderLayout;
2import java.awt.GridLayout;
3import java.awt.event.ActionEvent;
4import java.awt.event.ActionListener;
5import javax.swing.JButton;
6import javax.swing.JPanel;
7import javax.swing.JTextField;
8
9/**
10   A component that lets the user enter a number, using 
11   a button pad labeled with digits
12*/
13public class KeyPad extends JPanel
14{
15   /**
16      Constructs the keypad panel.
17   */
18   public KeyPad()
19   {  
20      setLayout(new BorderLayout());
21   
22      // add display field
23   
24      display = new JTextField();
25      add(display, "North");
26
27      // make button panel
28
29      buttonPanel = new JPanel();
30      buttonPanel.setLayout(new GridLayout(4, 3));
31      
32      // add digit buttons
33      
34      addButton("7");
35      addButton("8");
36      addButton("9");
37      addButton("4");
38      addButton("5");
39      addButton("6");
40      addButton("1");
41      addButton("2");
42      addButton("3");
43      addButton("0");      
44      addButton(".");
45      
46      // add clear entry button
47      
48      clearButton = new JButton("CE");
49      buttonPanel.add(clearButton);
50
51      class ClearButtonListener implements ActionListener
52      {  
53         public void actionPerformed(ActionEvent event)
54         {  
55            display.setText("");
56         }
57      }
58      ActionListener listener = new ClearButtonListener();      
59
60      clearButton.addActionListener(new 
61         ClearButtonListener());      
62      
63      add(buttonPanel, "Center");
64   }
65
66   /**
67      Adds a button to the button panel 
68      @param label the button label
69   */
70   private void addButton(final String label)
71   {  
72      class DigitButtonListener implements ActionListener
73      {  
74         public void actionPerformed(ActionEvent event)
75         {  
76
77            // don't add two decimal points
78            if (label.equals(".") 
79               && display.getText().indexOf(".") != -1) 
80               return;
81
82            // append label text to button
83            display.setText(display.getText() + label);
84         }
85      }
86
87      JButton button = new JButton(label);
88      buttonPanel.add(button);
89      ActionListener listener = new DigitButtonListener();
90      button.addActionListener(listener);
91   }
92
93   /** 
94      Gets the value that the user entered. 
95      @return the value in the text field of the keypad
96   */
97   public double getValue()
98   {  
99      return Double.parseDouble(display.getText());
100   }
101   
102   /** 
103      Clears the dislay. 
104   */
105   public void clear()
106   {  
107      display.setText("");
108   }
109   
110   private JPanel buttonPanel;
111   private JButton clearButton;
112   private JTextField display;
113}
114

File Bank.java

1import java.io.BufferedReader;
2import java.io.FileReader;
3import java.io.IOException;
4import java.util.ArrayList;
5import java.util.StringTokenizer;
6
7/**
8   A bank contains customers with bank accounts.
9*/
10public class Bank
11{  
12   /**
13      Constructs a bank with no customers.
14   */
15   public Bank()
16   {  
17      customers = new ArrayList();
18   }
19   
20   /**
21      Reads the customer numbers and pins 
22      and initializes the bank accounts.
23      @param filename the name of the customer file
24   */
25   public void readCustomers(String filename) 
26      throws IOException
27   {  
28      BufferedReader in = new BufferedReader
29         (new FileReader(filename));
30      boolean done = false;
31      while (!done)
32      {  
33         String inputLine = in.readLine();
34         if (inputLine == null) done = true; 
35         else
36         {  
37            StringTokenizer tokenizer 
38               = new StringTokenizer(inputLine);
39            int number 
40               = Integer.parseInt(tokenizer.nextToken());
41            int pin 
42               = Integer.parseInt(tokenizer.nextToken());
43
44            Customer c = new Customer(number, pin);
45            addCustomer(c);
46         }
47      }
48      in.close();
49   }
50   
51   /**
52      Adds a customer to the bank.
53      @param c the customer to add
54   */
55   public void addCustomer(Customer c)
56   {  
57      customers.add(c);
58   }
59   
60   /** 
61      Finds a customer in the bank.
62      @param aNumber a customer number
63      @param aPin a personal identification number
64      @return the matching customer, or null if no customer 
65      matches
66   */
67   public Customer findCustomer(int aNumber, int aPin)
68   {  
69      for (int i = 0; i < customers.size(); i++)
70      {  
71         Customer c = (Customer)customers.get(i);
72         if (c.match(aNumber, aPin))
73            return c;
74      }
75      return null;
76   }
77
78   private ArrayList customers;
79}
80
81

File Customer.java

1/**
2   A bank customer with a checking and savings account.
3*/
4public class Customer
5{  
6   /**
7      Constructs a customer with a given number and PIN.
8      @param aNumber the customer number
9      @param PIN the personal identification number
10   */
11   public Customer(int aNumber, int aPin)
12   {  
13      customerNumber = aNumber;
14      pin = aPin;
15      checkingAccount = new BankAccount();
16      savingsAccount = new BankAccount();
17   }
18   
19   /** 
20      Tests if this customer matches a customer number 
21      and PIN.
22      @param aNumber a customer number
23      @param aPin a personal identification number
24      @return true if the customer number and PIN match
25   */
26   public boolean match(int aNumber, int aPin)
27   {  
28      return customerNumber == aNumber && pin == aPin;
29   }
30   
31   /** 
32      Gets the checking account of this customer.
33      @return the checking account
34   */
35   public BankAccount getCheckingAccount()
36   {  
37      return checkingAccount;
38   }
39   
40   /** 
41      Gets the savings account of this customer.
42      @return the checking account
43   */
44   public BankAccount getSavingsAccount()
45   {  
46      return savingsAccount;
47   }
48
49   private int customerNumber;
50   private int pin;
51   private BankAccount checkingAccount;
52   private BankAccount savingsAccount;
53}