Contents [0/72] |
Object-Oriented Design & Patterns [1/72] |
Chapter Topics [2/72] |
List Iterators [3/72] |
LinkedList<String> list = . . .;
ListIterator<String> iterator = list.listIterator();
while (iterator.hasNext())
{
String current = iterator.next();
. . .
}
Classical List Data Structure [4/72] |
Link currentLink = list.head;
while (currentLink != null)
{
Object current = currentLink.data;
currentLink = currentLink.next;
}
High-Level View of Data Structures [5/72] |
List with Cursor [6/72] |
for (list.reset(); list.hasNext(); list.next())
{
Object x = list.get();
. . .
}
The Pattern Concept [7/72] |
Short Passages Pattern [8/72] |
Short Passages Pattern [9/72] |
a lengthy description of the problem, including
Short Passages Pattern [10/72] |
Iterator Pattern [11/72] |
Iterator Pattern [12/72] |
Iterator Pattern [13/72] |
Iterator Pattern [14/72] |
Name in
Design Pattern |
Actual Name
(linked lists) |
Aggregate |
List |
ConcreteAggregate |
LinkedList |
Iterator |
ListIterator |
ConcreteIterator |
anonymous class implementing ListIterator |
createIterator() |
listIterator() |
next() |
next() |
isDone() |
opposite of hasNext() |
currentItem() |
return value of hasNext() |
Model/View/Controller [15/72] |
Model/View/Controller [16/72] |
Model/View/Controller [17/72] |
Model/View/Controller [18/72] |
Model/View/Controller [19/72] |
Observer Pattern [20/72] |
Observer Pattern [21/72] |
Observer Pattern [22/72] |
Names in Observer Pattern [23/72] |
Name in Design Pattern |
Actual Name (Swing buttons) |
Subject |
JButton |
Observer |
ActionListener |
ConcreteObserver |
the class that implements the ActionListener
interface type |
attach() |
addActionListener() |
notify() | actionPerformed() |
Layout Managers [24/72] |
Layout Managers [25/72] |
Layout Managers [26/72] |
Layout Managers [27/72] |
Layout Managers [28/72] |
Voice Mail System GUI [29/72] |
Voice Mail System GUI [30/72] |
Voice Mail System GUI [31/72] |
JPanel keyPanel = new JPanel();
keyPanel.setLayout(new GridLayout(4, 3));
for (int i = 0; i < 12; i++)
{
JButton keyButton = new JButton(...);
keyPanel.add(keyButton);
keyButton.addActionListener(...);
}
Voice Mail System GUI [32/72] |
JPanel speakerPanel = new JPanel();
speakerPanel.setLayout(new BorderLayout());
speakerPanel.add(new JLabel("Speaker:"), BorderLayout.NORTH);
speakerField = new JTextArea(10, 25);
speakerPanel.add(speakerField, BorderLayout.CENTER);
Voice Mail System GUI [33/72] |
file:horstmann/ch05_mailgui/Telephone.java [source] [doc-public] [doc-private]
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
package horstmann.ch05_mailgui; import java.awt.BorderLayout; import java.awt.GridLayout; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTextArea; /** Presents a phone GUI for the voice mail system. */ public class Telephone { /** Constructs a telephone with a speaker, keypad, and microphone. */ public Telephone() { JPanel speakerPanel = new JPanel(); speakerPanel.setLayout(new BorderLayout()); speakerPanel.add(new JLabel("Speaker:"), BorderLayout.NORTH); speakerField = new JTextArea(10, 25); speakerPanel.add(speakerField, BorderLayout.CENTER); String keyLabels = "123456789*0#"; JPanel keyPanel = new JPanel(); keyPanel.setLayout(new GridLayout(4, 3)); for (int i = 0; i < keyLabels.length(); i++) { final String label = keyLabels.substring(i, i + 1); JButton keyButton = new JButton(label); keyPanel.add(keyButton); keyButton.addActionListener(event -> connect.dial(label)); } final JTextArea microphoneField = new JTextArea(10,25); JButton speechButton = new JButton("Send speech"); speechButton.addActionListener(event -> { connect.record(microphoneField.getText()); microphoneField.setText(""); }); JButton hangupButton = new JButton("Hangup"); hangupButton.addActionListener(event -> connect.hangup()); JPanel buttonPanel = new JPanel(); buttonPanel.add(speechButton); buttonPanel.add(hangupButton); JPanel microphonePanel = new JPanel(); microphonePanel.setLayout(new BorderLayout()); microphonePanel.add(new JLabel("Microphone:"), BorderLayout.NORTH); microphonePanel.add(microphoneField, BorderLayout.CENTER); microphonePanel.add(buttonPanel, BorderLayout.SOUTH); JFrame frame = new JFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.add(speakerPanel, BorderLayout.NORTH); frame.add(keyPanel, BorderLayout.CENTER); frame.add(microphonePanel, BorderLayout.SOUTH); frame.pack(); frame.setVisible(true); } /** Give instructions to the mail system user. */ public void speak(String output) { speakerField.setText(output); } public void run(Connection c) { connect = c; } private JTextArea speakerField; private Connection connect; }
Custom Layout Manager [34/72] |
The LayoutManager Interface Type [35/72] |
public interface LayoutManager
{
void layoutContainer(Container parent);
Dimension minimumLayoutSize(Container parent);
Dimension preferredLayoutSize(Container parent);
void addLayoutComponent(String name, Component comp);
void removeLayoutComponent(Component comp);
}
Form Layout [36/72] |
file:horstmann/ch05_layout/FormLayout.java [source] [doc-public] [doc-private]
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
package horstmann.ch05_layout; import java.awt.Component; import java.awt.Container; import java.awt.Dimension; import java.awt.Insets; import java.awt.LayoutManager; /** A layout manager that lays out components along a central axis */ public class FormLayout implements LayoutManager { public Dimension preferredLayoutSize(Container parent) { Component[] components = parent.getComponents(); left = 0; right = 0; height = 0; for (int i = 0; i < components.length; i += 2) { Component cleft = components[i]; Component cright = components[i + 1]; Dimension dleft = cleft.getPreferredSize(); Dimension dright = cright.getPreferredSize(); left = Math.max(left, dleft.width); right = Math.max(right, dright.width); height = height + Math.max(dleft.height, dright.height); } return new Dimension(left + GAP + right, height); } public Dimension minimumLayoutSize(Container parent) { return preferredLayoutSize(parent); } public void layoutContainer(Container parent) { preferredLayoutSize(parent); // Sets left, right Component[] components = parent.getComponents(); Insets insets = parent.getInsets(); int xcenter = insets.left + left; int y = insets.top; for (int i = 0; i < components.length; i += 2) { Component cleft = components[i]; Component cright = components[i + 1]; Dimension dleft = cleft.getPreferredSize(); Dimension dright = cright.getPreferredSize(); int height = Math.max(dleft.height, dright.height); cleft.setBounds(xcenter - dleft.width, y + (height - dleft.height) / 2, dleft.width, dleft.height); cright.setBounds(xcenter + GAP, y + (height - dright.height) / 2, dright.width, dright.height); y += height; } } public void addLayoutComponent(String name, Component comp) {} public void removeLayoutComponent(Component comp) {} private int left; private int right; private int height; private static final int GAP = 6; }
file:horstmann/ch05_layout/FormLayoutTester.java [source] [doc-public] [doc-private]
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package horstmann.ch05_layout; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JTextField; public class FormLayoutTester { public static void main(String[] args) { JFrame frame = new JFrame(); frame.setLayout(new FormLayout()); frame.add(new JLabel("Name")); frame.add(new JTextField(15)); frame.add(new JLabel("Address")); frame.add(new JTextField(20)); frame.add(new JLabel("City")); frame.add(new JTextField(10)); frame.add(new JLabel("State")); frame.add(new JTextField(2)); frame.add(new JLabel("ZIP")); frame.add(new JTextField(5)); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.pack(); frame.setVisible(true); } }
Strategy Pattern [37/72] |
Comparator<Country> comp = new CountryComparatorByName();
Collections.sort(countries, comp);
Strategy Pattern [38/72] |
Strategy Pattern [39/72] |
Strategy Pattern: Layout Management [40/72] |
Name in
Design Pattern |
Actual Name
(layout management) |
Context |
Container |
Strategy |
LayoutManager |
ConcreteStrategy |
a layout manager such as BorderLayout |
doWork() |
a method such as layoutContainer |
Strategy Pattern: Sorting [41/72] |
Name in
Design Pattern |
Actual Name
(sorting) |
Context |
Collections |
Strategy |
Comparator |
ConcreteStrategy |
a class that implements Comparator |
doWork() |
compare |
Containers and Components [42/72] |
Composite Pattern [43/72] |
Composite Pattern [44/72] |
Composite Pattern [45/72] |
Name in
Design Pattern |
Actual Name
(AWT components) |
Primitive |
Component |
Composite |
Container |
Leaf |
a component without children
(e.g. JButton) |
method() |
a method of Component
(e.g. getPreferredSize) |
Scroll Bars [46/72] |
JScrollPane pane = new JScrollPane(component);
Scroll Bars [47/72] |
Decorator Pattern [48/72] |
Decorator Pattern [49/72] |
Decorator Pattern [50/72] |
Decorator Pattern: Scroll Bars [51/72] |
Name in
Design Pattern |
Actual Name
(scroll bars) |
Component | Component |
ConcreteComponent | JTextArea |
Decorator | JScrollPane |
method() |
a method of Component
(e.g. paint) |
Streams [52/72] |
InputStreamReader reader = new InputStreamReader(System.in);
BufferedReader console = new BufferedReader(reader);
Decorator Pattern: Input Streams [53/72] |
Name in
Design Pattern |
Actual Name
(input streams) |
Component | Reader |
ConcreteComponent | InputStreamReader |
Decorator | BufferedReader |
method() |
read |
How to Recognize Patterns [54/72] |
Litmus Test [55/72] |
Border b = new EtchedBorder()
component.setBorder(b);
Litmus Test [56/72] |
Putting Patterns to Work [57/72] |
file:horstmann/ch05_invoice/LineItem.java [source] [doc-public] [doc-private]
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
package horstmann.ch05_invoice; /** A line item in an invoice. */ public interface LineItem { /** Gets the price of this line item. @return the price */ double getPrice(); /** Gets the description of this line item. @return the description */ String toString(); }
file:horstmann/ch05_invoice/Product.java [source] [doc-public] [doc-private]
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
package horstmann.ch05_invoice; /** A product with a price and description. */ public class Product implements LineItem { /** Constructs a product. @param description the description @param price the price */ public Product(String description, double price) { this.description = description; this.price = price; } public double getPrice() { return price; } public String toString() { return description; } private String description; private double price; }
Bundles [58/72] |
file:horstmann/ch05_invoice/Bundle.java [source] [doc-public] [doc-private]
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package horstmann.ch05_invoice; import java.util.ArrayList; /** A bundle of line items that is again a line item. */ public class Bundle implements LineItem { /** Constructs a bundle with no items. */ public Bundle() { items = new ArrayList<LineItem>(); } /** Adds an item to the bundle. @param item the item to add */ public void add(LineItem item) { items.add(item); } public double getPrice() { double price = 0; for (LineItem item : items) price += item.getPrice(); return price; } public String toString() { String description = "Bundle: "; for (int i = 0; i < items.size(); i++) { if (i > 0) description += ", "; description += items.get(i).toString(); } return description; } private ArrayList<LineItem> items; }
Bundles [59/72] |
Discounted Items [60/72] |
file:horstmann/ch05_invoice/DiscountedItem.java [source] [doc-public] [doc-private]
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package horstmann.ch05_invoice; /** A decorator for an item that applies a discount. */ public class DiscountedItem implements LineItem { /** Constructs a discounted item. @param item the item to be discounted @param discount the discount percentage */ public DiscountedItem(LineItem item, double discount) { this.item = item; this.discount = discount; } public double getPrice() { return item.getPrice() * (1 - discount / 100); } public String toString() { return item.toString() + " (Discount " + discount + "%)"; } private LineItem item; private double discount; }
Discounted Items [61/72] |
Model/View Separation [62/72] |
Change Listeners [63/72] |
Change Listeners [64/72] |
final Invoice invoice = new Invoice();
final JTextArea textArea = new JTextArea(20, 40);
ChangeListener listener = new
ChangeListener()
{
public void stateChanged(ChangeEvent event)
{
textArea.setText(...);
}
};
Observing the Invoice [65/72] |
Iterating Through Invoice Items [66/72] |
Iterators [67/72] |
file:horstmann/ch05_invoice/Invoice.java [source] [doc-public] [doc-private]
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
package horstmann.ch05_invoice; import java.util.ArrayList; import java.util.Iterator; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; /** An invoice for a sale, consisting of line items. */ public class Invoice { /** Constructs a blank invoice. */ public Invoice() { items = new ArrayList<LineItem>(); listeners = new ArrayList<ChangeListener>(); } /** Adds an item to the invoice. @param item the item to add */ public void addItem(LineItem item) { items.add(item); // Notify all observers of the change to the invoice ChangeEvent event = new ChangeEvent(this); for (ChangeListener listener : listeners) listener.stateChanged(event); } /** Adds a change listener to the invoice. @param listener the change listener to add */ public void addChangeListener(ChangeListener listener) { listeners.add(listener); } /** Gets an iterator that iterates through the items. @return an iterator for the items */ public Iterator<LineItem> getItems() { return new Iterator<LineItem>() { public boolean hasNext() { return current < items.size(); } public LineItem next() { return items.get(current++); } public void remove() { throw new UnsupportedOperationException(); } private int current = 0; }; } public String format(InvoiceFormatter formatter) { String r = formatter.formatHeader(); Iterator<LineItem>iter = getItems(); while (iter.hasNext()) r += formatter.formatLineItem(iter.next()); return r + formatter.formatFooter(); } private ArrayList<LineItem> items; private ArrayList<ChangeListener> listeners; }
Iterators [68/72] |
Formatting Invoices [69/72] |
Formatting Invoices [70/72] |
file:horstmann/ch05_invoice/InvoiceFormatter.java [source] [doc-public] [doc-private]
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package horstmann.ch05_invoice; /** This interface describes the tasks that an invoice formatter needs to carry out. */ public interface InvoiceFormatter { /** Formats the header of the invoice. @return the invoice header */ String formatHeader(); /** Formats a line item of the invoice. @return the formatted line item */ String formatLineItem(LineItem item); /** Formats the footer of the invoice. @return the invoice footer */ String formatFooter(); }
file:horstmann/ch05_invoice/SimpleFormatter.java [source] [doc-public] [doc-private]
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package horstmann.ch05_invoice; /** A simple invoice formatter. */ public class SimpleFormatter implements InvoiceFormatter { public String formatHeader() { total = 0; return " I N V O I C E\n\n\n"; } public String formatLineItem(LineItem item) { total += item.getPrice(); return (String.format( "%s: $%.2f\n",item.toString(),item.getPrice())); } public String formatFooter() { return (String.format("\n\nTOTAL DUE: $%.2f\n", total)); } private double total; }
file:horstmann/ch05_invoice/InvoiceTester.java [source] [doc-public] [doc-private]
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
package horstmann.ch05_invoice; import java.awt.BorderLayout; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.event.ChangeListener; /** A program that tests the invoice classes. */ public class InvoiceTester { public static void main(String[] args) { final Invoice invoice = new Invoice(); final InvoiceFormatter formatter = new SimpleFormatter(); // This text area will contain the formatted invoice final JTextArea textArea = new JTextArea(20, 40); // When the invoice changes, update the text area ChangeListener listener = event -> textArea.setText(invoice.format(formatter)); invoice.addChangeListener(listener); // Add line items to a combo box final JComboBox<LineItem> combo = new JComboBox<>(); Product hammer = new Product("Hammer", 19.95); Product nails = new Product("Assorted nails", 9.95); combo.addItem(hammer); Bundle bundle = new Bundle(); bundle.add(hammer); bundle.add(nails); combo.addItem(new DiscountedItem(bundle, 10)); // Make a button for adding the currently selected // item to the invoice JButton addButton = new JButton("Add"); addButton.addActionListener(event -> { LineItem item = (LineItem) combo.getSelectedItem(); invoice.addItem(item); }); // Put the combo box and the add button into a panel JPanel panel = new JPanel(); panel.add(combo); panel.add(addButton); // Add the text area and panel to the content pane JFrame frame = new JFrame(); frame.add(new JScrollPane(textArea), BorderLayout.CENTER); frame.add(panel, BorderLayout.SOUTH); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.pack(); frame.setVisible(true); } }
Formatting Invoices [71/72] |
Formatting Invoices [72/72] |
Revised: 2007/09/11 16:27