Contents [0/65] |
Object-Oriented Design & Patterns [1/65] |
Chapter Topics [2/65] |
Modeling Specialization [3/65] |
Modeling Specialization [4/65] |
Modeling Specialization [5/65] |
Manager Methods and Fields [6/65] |
The Super/Sub Terminology [7/65] |
The Super/Sub Terminology [8/65] |
Inheritance Hierarchies [9/65] |
Inheritance Hierarchies [10/65] |
The Substitution Principle [11/65] |
Invoking Superclass Methods [12/65] |
Invoking Superclass Methods [13/65] |
Invoking Superclass Constructors [14/65] |
Preconditions [15/65] |
public class Employee
{
/**
Sets the employee salary to a given value.
@param aSalary the new salary
@precondition aSalary > 0
*/
public void setSalary(double aSalary) { ... }
}
Manager m = new Manager();
Employee e = m;
e.setSalary(50000);
Postconditions, Visibility, Exceptions [16/65] |
Graphic Programming with Inheritance [17/65] |
Mouse Listeners [18/65] |
public interface MouseListener
{
void mouseClicked(MouseEvent event);
void mousePressed(MouseEvent event);
void mouseReleased(MouseEvent event);
void mouseEntered(MouseEvent event);
void mouseExited(MouseEvent event);
}
public interface MouseMotionListener
{
void mouseMoved(MouseEvent event);
void mouseDragged(MouseEvent event);
}
Mouse Adapters [19/65] |
public class MouseAdapter implements MouseListener
{
public void mouseClicked(MouseEvent event) {}
public void mousePressed(MouseEvent event) {}
public void mouseReleased(MouseEvent event) {}
public void mouseEntered(MouseEvent event) {}
public void mouseExited(MouseEvent event) {}
}
addMouseListener(new
MouseAdapter()
{
public void mousePressed(MouseEvent event)
{
mouse action goes here
}
});
Car Mover Program [20/65] |
file:horstmann/ch06_car/CarComponent.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
package horstmann.ch06_car; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionAdapter; import javax.swing.JComponent; /** A component that shows a scene composed of items. */ @SuppressWarnings("serial") public class CarComponent extends JComponent { public CarComponent() { car = new CarShape(20, 20, 50); addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent event) { mousePoint = event.getPoint(); if (!car.contains(mousePoint)) mousePoint = null; } }); addMouseMotionListener(new MouseMotionAdapter() { public void mouseDragged(MouseEvent event) { if (mousePoint == null) return; Point lastMousePoint = mousePoint; mousePoint = event.getPoint(); double dx = mousePoint.getX() - lastMousePoint.getX(); double dy = mousePoint.getY() - lastMousePoint.getY(); car.translate((int) dx, (int) dy); repaint(); } }); } public void paintComponent(Graphics g) { Graphics2D g2 = (Graphics2D) g; car.draw(g2); } private CarShape car; private Point mousePoint; }
file:horstmann/ch06_car/CarMover.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
package horstmann.ch06_car; import javax.swing.JFrame; /** A program that allows users to move a car with the mouse. */ public class CarMover { public static void main(String[] args) { JFrame frame = new JFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.add(new CarComponent()); frame.setSize(FRAME_WIDTH, FRAME_HEIGHT); frame.setVisible(true); } private static final int FRAME_WIDTH = 400; private static final int FRAME_HEIGHT = 400; }
file:horstmann/ch06_car/CarShape.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
package horstmann.ch06_car; import java.awt.Graphics2D; import java.awt.geom.Ellipse2D; import java.awt.geom.Line2D; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; /** A car shape. */ public class CarShape { /** Constructs a car shape. @param x the left of the bounding rectangle @param y the top of the bounding rectangle @param width the width of the bounding rectangle */ public CarShape(int x, int y, int width) { this.x = x; this.y = y; this.width = width; } public void draw(Graphics2D g2) { Rectangle2D.Double body = new Rectangle2D.Double(x, y + width / 6, width - 1, width / 6); Ellipse2D.Double frontTire = new Ellipse2D.Double(x + width / 6, y + width / 3, width / 6, width / 6); Ellipse2D.Double rearTire = new Ellipse2D.Double(x + width * 2 / 3, y + width / 3, width / 6, width / 6); // The bottom of the front windshield Point2D.Double r1 = new Point2D.Double(x + width / 6, y + width / 6); // The front of the roof Point2D.Double r2 = new Point2D.Double(x + width / 3, y); // The rear of the roof Point2D.Double r3 = new Point2D.Double(x + width * 2 / 3, y); // The bottom of the rear windshield Point2D.Double r4 = new Point2D.Double(x + width * 5 / 6, y + width / 6); Line2D.Double frontWindshield = new Line2D.Double(r1, r2); Line2D.Double roofTop = new Line2D.Double(r2, r3); Line2D.Double rearWindshield = new Line2D.Double(r3, r4); g2.draw(body); g2.draw(frontTire); g2.draw(rearTire); g2.draw(frontWindshield); g2.draw(roofTop); g2.draw(rearWindshield); } public boolean contains(Point2D p) { return x <= p.getX() && p.getX() <= x + width && y <= p.getY() && p.getY() <= y + width / 2; } public void translate(int dx, int dy) { x += dx; y += dy; } private int x; private int y; private int width; }
Car Mover Program [21/65] |
Scene Editor [22/65] |
Scene Editor [23/65] |
The SceneShape Interface Type [24/65] |
The SceneShape Interface Type [25/65] |
The SceneShape Interface Type [26/65] |
public interface SceneShape
CarShape and HouseShape Classes [27/65] |
public class CarShape implements SceneShape
{
...
public void setSelected(boolean b) { selected = b; }
public boolean isSelected() { return selected; }
private boolean selected;
}
public class HouseShape implements SceneShape
{
...
public void setSelected(boolean b) { selected = b; }
public boolean isSelected() { return selected; }
private boolean selected;
}
Abstract Classes [28/65] |
public class SelectableShape implements Item
{
public void setSelected(boolean b) { selected = b; }
public boolean isSelected() { return selected; }
private boolean selected;
}
Abstract Classes [29/65] |
Abstract Classes [30/65] |
SelectableShape s = new SelectableShape(); // NO
SelectableShape s = new HouseShape(); // OK
Abstract Classes and Interface Types [31/65] |
Scene Editor [32/65] |
file:horstmann/ch06_scene1/SceneComponent.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
88
89
90
91
92
93
94
95
package horstmann.ch06_scene1; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionAdapter; import java.util.ArrayList; import javax.swing.JComponent; /** A component that shows a scene composed of shapes. */ @SuppressWarnings("serial") public class SceneComponent extends JComponent { public SceneComponent() { shapes = new ArrayList<SceneShape>(); addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent event) { mousePoint = event.getPoint(); for (SceneShape s : shapes) { if (s.contains(mousePoint)) s.setSelected(!s.isSelected()); } repaint(); } }); addMouseMotionListener(new MouseMotionAdapter() { public void mouseDragged(MouseEvent event) { Point lastMousePoint = mousePoint; mousePoint = event.getPoint(); for (SceneShape s : shapes) { if (s.isSelected()) { double dx = mousePoint.getX() - lastMousePoint.getX(); double dy = mousePoint.getY() - lastMousePoint.getY(); s.translate((int) dx, (int) dy); } } repaint(); } }); } /** Adds a shape to the scene. @param s the shape to add */ public void add(SceneShape s) { shapes.add(s); repaint(); } /** Removes all selected shapes from the scene. */ public void removeSelected() { for (int i = shapes.size() - 1; i >= 0; i--) { SceneShape s = shapes.get(i); if (s.isSelected()) shapes.remove(i); } repaint(); } public void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2 = (Graphics2D) g; for (SceneShape s : shapes) { s.draw(g2); if (s.isSelected()) s.drawSelection(g2); } } private ArrayList<SceneShape> shapes; private Point mousePoint; }
file:horstmann/ch06_scene1/SceneEditor.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.ch06_scene1; import java.awt.BorderLayout; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; /** A program that allows users to edit a scene composed of items. */ public class SceneEditor { public static void main(String[] args) { JFrame frame = new JFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); final SceneComponent scene = new SceneComponent(); JButton houseButton = new JButton("House"); houseButton.addActionListener(event -> scene.add(new HouseShape(20, 20, 50))); JButton carButton = new JButton("Car"); carButton.addActionListener(event -> scene.add(new CarShape(20, 20, 50))); JButton removeButton = new JButton("Remove"); removeButton.addActionListener(event -> scene.removeSelected()); JPanel buttons = new JPanel(); buttons.add(houseButton); buttons.add(carButton); buttons.add(removeButton); frame.add(scene, BorderLayout.CENTER); frame.add(buttons, BorderLayout.NORTH); frame.setSize(300, 300); frame.setVisible(true); } }
file:horstmann/ch06_scene1/HouseShape.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
package horstmann.ch06_scene1; import java.awt.Graphics2D; import java.awt.geom.Line2D; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; /** A house shape. */ public class HouseShape extends SelectableShape { /** Constructs a house shape. @param x the left of the bounding rectangle @param y the top of the bounding rectangle @param width the width of the bounding rectangle */ public HouseShape(int x, int y, int width) { this.x = x; this.y = y; this.width = width; } public void draw(Graphics2D g2) { Rectangle2D.Double base = new Rectangle2D.Double(x, y + width, width, width); // The left bottom of the roof Point2D.Double r1 = new Point2D.Double(x, y + width); // The top of the roof Point2D.Double r2 = new Point2D.Double(x + width / 2, y); // The right bottom of the roof Point2D.Double r3 = new Point2D.Double(x + width, y + width); Line2D.Double roofLeft = new Line2D.Double(r1, r2); Line2D.Double roofRight = new Line2D.Double(r2, r3); g2.draw(base); g2.draw(roofLeft); g2.draw(roofRight); } public void drawSelection(Graphics2D g2) { Rectangle2D.Double base = new Rectangle2D.Double(x, y + width, width, width); g2.fill(base); } public boolean contains(Point2D p) { return x <= p.getX() && p.getX() <= x + width && y <= p.getY() && p.getY() <= y + 2 * width; } public void translate(int dx, int dy) { x += dx; y += dy; } private int x; private int y; private int width; }
Uniform Highlighting Technique [33/65] |
Uniform Highlighting Technique [34/65] |
Template Method [35/65] |
file:horstmann/ch06_scene2/SelectableShape.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.ch06_scene2; import java.awt.Graphics2D; /** A shape that manages its selection state. */ public abstract class SelectableShape implements SceneShape { public void setSelected(boolean b) { selected = b; } public boolean isSelected() { return selected; } public void drawSelection(Graphics2D g2) { translate(1, 1); draw(g2); translate(1, 1); draw(g2); translate(-2, -2); } private boolean selected; }
file:horstmann/ch06_scene2/HouseShape.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
package horstmann.ch06_scene2; import java.awt.Graphics2D; import java.awt.geom.Line2D; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; /** A house shape. */ public class HouseShape extends SelectableShape { /** Constructs a house shape. @param x the left of the bounding rectangle @param y the top of the bounding rectangle @param width the width of the bounding rectangle */ public HouseShape(int x, int y, int width) { this.x = x; this.y = y; this.width = width; } public void draw(Graphics2D g2) { Rectangle2D.Double base = new Rectangle2D.Double(x, y + width, width, width); // The left bottom of the roof Point2D.Double r1 = new Point2D.Double(x, y + width); // The top of the roof Point2D.Double r2 = new Point2D.Double(x + width / 2, y); // The right bottom of the roof Point2D.Double r3 = new Point2D.Double(x + width, y + width); Line2D.Double roofLeft = new Line2D.Double(r1, r2); Line2D.Double roofRight = new Line2D.Double(r2, r3); g2.draw(base); g2.draw(roofLeft); g2.draw(roofRight); } public boolean contains(Point2D p) { return x <= p.getX() && p.getX() <= x + width && y <= p.getY() && p.getY() <= y + 2 * width; } public void translate(int dx, int dy) { x += dx; y += dy; } private int x; private int y; private int width; }
TEMPLATE METHOD Pattern [36/65] |
TEMPLATE METHOD Pattern [37/65] |
TEMPLATE METHOD Pattern [38/65] |
TEMPLATE METHOD Pattern [39/65] |
Name in
Design Pattern |
Actual Name
(Selectable shapes) |
AbstractClass |
SelectableShape |
ConcreteClass |
CarShape,
HouseShape |
templateMethod() |
drawSelection |
primitiveOp1(),
primitiveOp2() |
translate,
draw |
Compound Shapes [40/65] |
GeneralPath path = new GeneralPath();
path.append(new Rectangle(...), false);
path.append(new Triangle(...), false);
g2.draw(path);
file:horstmann/ch06_scene3/CompoundShape.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
package horstmann.ch06_scene3; import java.awt.Graphics2D; import java.awt.Shape; import java.awt.geom.AffineTransform; import java.awt.geom.GeneralPath; import java.awt.geom.Point2D; /** A scene shape that is composed of multiple geometric shapes. */ public abstract class CompoundShape extends SelectableShape { public CompoundShape() { path = new GeneralPath(); } protected void add(Shape s) { path.append(s, false); } public boolean contains(Point2D aPoint) { return path.contains(aPoint); } public void translate(int dx, int dy) { path.transform( AffineTransform.getTranslateInstance(dx, dy)); } public void draw(Graphics2D g2) { g2.draw(path); } private GeneralPath path; }
file:horstmann/ch06_scene3/HouseShape.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.ch06_scene3; import java.awt.geom.Line2D; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; /** A house shape. */ public class HouseShape extends CompoundShape { /** Constructs a house shape. @param x the left of the bounding rectangle @param y the top of the bounding rectangle @param width the width of the bounding rectangle */ public HouseShape(int x, int y, int width) { Rectangle2D.Double base = new Rectangle2D.Double(x, y + width, width, width); // The left bottom of the roof Point2D.Double r1 = new Point2D.Double(x, y + width); // The top of the roof Point2D.Double r2 = new Point2D.Double(x + width / 2, y); // The right bottom of the roof Point2D.Double r3 = new Point2D.Double(x + width, y + width); Line2D.Double roofLeft = new Line2D.Double(r1, r2); Line2D.Double roofRight = new Line2D.Double(r2, r3); add(base); add(roofLeft); add(roofRight); } }
Compound Shapes [41/65] |
Access to Superclass Features [42/65] |
public HouseShape()
{
add(new Rectangle(...));
add(new Triangle(...));
}
Protected Access [43/65] |
Hierarchy of Swing Components [44/65] |
int getWidth()
int getHeight()
Dimension getPreferredSize()
void setBackground(Color c)
. . .
Hierarchy of Swing Components [45/65] |
Hierarchy of Swing Components [46/65] |
Look and Feel [47/65] |
Hierarchy of Swing Components [48/65] |
Hierarchy of Geometrical Shapes [49/65] |
Point
Rectangle
Polygon
Point2D
Rectangle2D
RoundRectangle2D
Line2D
Ellipse2D
Arc2D
QuadCurve2D
CubicCurve2D
GeneralPath
Area
Hierarchy of Geometrical Shapes [50/65] |
Rectangular Shapes [51/65] |
Rectangle2D
RoundRectangle2D
Ellipse2D
Arc2D
getCenterX/getCenterY
getMinX/getMinY
getMaxX/getMaxY
getWidth/getHeight
setFrameFromCenter/setFrameFromDiagonal
Float/Double Classes [52/65] |
Rectangle2D.Double
Rectangle2D.Float
Float/Double Classes [53/65] |
Float/Double Classes [54/65] |
public class Rectangle2D
{
public static class Float extends Rectangle2D
{
public double getX() { return x; }
public double getY() { return y; }
public double getWidth() { return width; }
public double getHeight() { return height;}
public void setRect(float x, float y, float w, float h)
{
this.x = x; this.y = y;
this.width = w; this.height = h;
}
public void setRect(double x, double y,
double w, double h)
{
this.x = (float)x; this.y = (float)y;
this.width = (float)w; this.height = (float)h;
}
...
public float x;
public float y;
public float width;
public float height;
}
. . .
Float/Double Classes [55/65] |
. . .
public static class Double extends Rectangle2D
public double getX() { return x; }
public double getY() { return y; }
public double getWidth() { return width; }
public double getHeight() { return height;}
public void setRect(double x, double y,
double w, double h)
{
this.x = x; this.y = y;
this.width = w; this.height = h;
}
...
public double x;
public double y;
public double width;
public double height;
}
...
}
Float/Double Classes [56/65] |
public boolean contains(double x, double y)
{
double x0 = getX();
double y0 = getY();
return x >= x0 && y >= y0 &&
x < x0 + getWidth() &&
y < y0 + getHeight();
}
TEMPLATE METHOD Pattern [57/65] |
Name in
Design Pattern |
Actual Name
(Rectangles) |
AbstractClass |
Rectangle |
ConcreteClass |
Rectangle2D.Double |
templateMethod() |
contains |
primitiveOpn() |
getX, getY, getWidth, getHeight |
Hierarchy of Exception Classes [58/65] |
Hierarchy of Exception Classes [59/65] |
Catching Exceptions [60/65] |
try
{
code that may throw exceptions
}
catch (ExceptionType1 exception1)
{
handler for ExceptionType1
}
catch (ExceptionType2 exception1)
{
handler for ExceptionType2
}
Defining Exception Classes [61/65] |
public class IllegalFormatException extends Exception
{
public IllegalFormatException() {}
public IllegalFormatException(String reason)
{ super(reason); }
}
When Not to Use Inheritance [62/65] |
public class Point
{
public Point(int anX, int aY) { ... }
public void translate(int dx, int dy) { ... }
private int x;
private int y;
}
public class Circle extends Point // DON'T
{
public Circle(Point center, int radius) { ... }
public void draw(Graphics g) { ... }
private int radius;
}
When Not to Use Inheritance [63/65] |
public class Rectangle extends Point // DON'T
{
public Rectangle(Point corner1, Point corner2) { ... }
public void draw(Graphics g) { ... }
public void translate(int dx, int dy) { ... }
private Point other;
}
When Not to Use Inheritance [64/65] |
public void translate(int dx, int dy)
{
super.translate(dx, dy);
other.translate(dx, dy);
}
When Not to Use Inheritance [65/65] |
public class Stack<T> extends Vector<T> // DON'T
{
T pop() { ... }
void push(T item) { ... }
...
}
public class Stack<T>
{
...
private ArrayList<T> elements;
}
Revised: 2007/09/11 16:28