107
Unit 13 Decorator Summary prepared by Kirk Scott 1

Unit 13 Decorator

  • Upload
    kaya

  • View
    34

  • Download
    0

Embed Size (px)

DESCRIPTION

Unit 13 Decorator. Summary prepared by Kirk Scott. Design Patterns in Java Chapter 27 Decorator. Summary prepared by Kirk Scott. The Introduction Before the Introduction. Suppose you have a set of functionalities where you would like to mix and match the functionalities together - PowerPoint PPT Presentation

Citation preview

Page 1: Unit 13 Decorator

1

Unit 13Decorator

Summary prepared by Kirk Scott

Page 2: Unit 13 Decorator

2

Design Patterns in JavaChapter 27Decorator

Summary prepared by Kirk Scott

Page 3: Unit 13 Decorator

3

The Introduction Before the Introduction

• Suppose you have a set of functionalities where you would like to mix and match the functionalities together

• You would like to be able to create objects with various functionalities

• This can be accomplished by repeated, wrapped construction (nested construction)

Page 4: Unit 13 Decorator

4

• Let one object be the result of one construction sequence

• Calling a given method on that object results in one subset of functionalities

• Let another object be the result of another construction sequence

• Calling the same method on the other object results in a different subset of functionalities

Page 5: Unit 13 Decorator

5

• This chapter uses streams and writers from the Java API as the first example of the decorator pattern

• It uses mathematical functions as the second example

• This set of overheads will only cover the first example from the book

• It will present another example that does not come from the book

Page 6: Unit 13 Decorator

6

• The book previews the definition of the pattern with observations along these lines:

• Extending a code base usually means adding classes to a design or methods to classes

• The Decorator design pattern supports extension by allowing a program at run time to construct objects that can have varying behavior

Page 7: Unit 13 Decorator

7

Book Definition of Pattern

• Book definition:• The intent of Decorator is to let you compose

new variations of an operation at runtime.

Page 8: Unit 13 Decorator

8

A Classic Example: Streams and Writers

• The Java API includes a set of classes that are related in such a way that they illustrate the Decorator design pattern

• These are the stream and writer classes which are used for file I/O and other purposes

• Let a generic FileReader or FileWriter be constructed in a program

• It is connected to an external file

Page 9: Unit 13 Decorator

9

• It is possible to pass the generic reader or writer as a construction parameter when making a more specific kind of reader or writer

• The new reader or writer adds I/O functionalities that don’t exist in the generic reader or writer

• The book illustrates this idea in the code on the following overhead

Page 10: Unit 13 Decorator

10

• public class ShowDecorator• {• public static void main(String[] args) throws IOException• {• FileWriter file = new FileWriter("sample.txt");• BufferedWriter writer = new BufferedWriter(file);• writer.write("a small amount of sample text");• writer.newLine();• writer.close();• }• }

Page 11: Unit 13 Decorator

11

• The book gives the foregoing example simply to illustrate the process of construction

• It doesn’t comment specifically on the methods

• The FileWriter class and the BufferedWriter classes both have various write() methods that take various sets of parameters

Page 12: Unit 13 Decorator

12

• The decorator pattern opens up the possibility of overloading

• The BufferedWriter write() method may take different parameters from the write() method in the FileWriter class

• More importantly, calling write() on a BufferedWriter object may give different results from calling write() on a FileWriter object

Page 13: Unit 13 Decorator

13

• The PrintWriter class may be a slightly better illustration

• An instance is constructed the same way as the book’s BufferedWriter example

• FileWriter file = new FileWriter("sample.txt");• PrintWriter writer = new PrintWriter(file);

• The PrintWriter class has additional methods besides write(), including print() and println()

Page 14: Unit 13 Decorator

14

• From a print writer you gain the ability to write text to a file using the same method calls that you use to put it on the screen

• This is the third thing you can get by using the pattern

• You can add new methods to the class with different functionality

Page 15: Unit 13 Decorator

15

• Using the decorator pattern, programmers can write their own file I/O classes that build on the API classes

• The book’s next example builds a hierarchy of classes that make it possible to format text before writing it to a file

• The formatting will be simple things like making it upper case or lower case

Page 16: Unit 13 Decorator

16

• The book refers to these formatting classes as filter classes

• It begins the presentation of the topic with the UML diagram given on the next overhead

• This will require a little explanation, which is given afterwards

Page 17: Unit 13 Decorator

17

Page 18: Unit 13 Decorator

18

• Both the Writer and FilterWriter abstract classes exist in the Java API

• FilterWriter extends Writer• FilterWriter also contains an instance of Writer• This illustrates the basic plan• A FilterWriter wraps an instance of its

superclass, adding functionality that doesn’t exist in the superclass

Page 19: Unit 13 Decorator

19

• It is worth noting that structurally, this was the official design of the proxy pattern

• In the proxy, the decision was ultimately made that a proxy in spirit was better

• That meant just implementing a subclass without wrapping an instance of the superclass

• Before the discussion of decorator is over with, it might be interesting to consider that alternative

Page 20: Unit 13 Decorator

20

• The Java API textual documentation for the FilterWriter class is given on the following overhead

• When you read this documentation you realize that the API is preparing you to apply the Decorator design pattern if you want to

Page 21: Unit 13 Decorator

21

Java API Documentation of the Class FilterWriter

• Abstract class for writing filtered character streams.

• The abstract class FilterWriter itself provides default methods that pass all requests to the contained stream.

• Subclasses of FilterWriter should override some of these methods and may also provide additional methods and fields.

Page 22: Unit 13 Decorator

22

• The initial diagram for the book’s example is repeated on the next overhead

• Because the OozinozFilter class is a subclass of the FileWriter class, it will contain an instance variable of type Writer

• In other words, the decorator structure is inherent in the Java API classes

• the Java developers have decided this is the right structure• The user just extends the FilterWriter class and works with

the wrapped Writer

Page 23: Unit 13 Decorator

23

Page 24: Unit 13 Decorator

24

• Next, the book extends its example UML diagram

• It is shown on the overhead following the next one

• The diagram emphasizes that the OozinozFilter class contains a Writer (by inheritance from FilterWriter) by drawing the line directly from OozinozFilter to Writer

Page 25: Unit 13 Decorator

25

• The OozinozFilter class is abstract• The diagram also shows its concrete subclasses

which will be the actual filters in the example• Note again that the decorator structure of a

subclass containing a reference to a superclass object is imposed at the top, in the Java API

• The programmer makes use of the pattern by making a hierarchy of classes underneath that

Page 26: Unit 13 Decorator

26

Page 27: Unit 13 Decorator

27

• Each concrete filter will be constructed by passing in a writer

• All concrete filters ultimately descend from the Writer class

• Therefore, when constructing instances of a concrete filter, any other kind of filter can be passed in

• This goes back to CS 202, where you learn that you can pass in a subclass object for a superclass formal parameter

Page 28: Unit 13 Decorator

28

• The filter subclasses may inherit or override the concrete write() methods in the OozinozFilter class

• OozinozFilter also has an abstract write() method

• This will have to be implemented

Page 29: Unit 13 Decorator

29

• The filter classes are going to do their work, and differ, according to the functionality of their implementation of that method

• The write() method in question takes a single int at a time as its input parameter, representing a character

Page 30: Unit 13 Decorator

30

• The code for the OozinozFilter class is given on the next overhead

• It shows the implementations of the concrete methods and the definition of the abstract method

Page 31: Unit 13 Decorator

31

• public abstract class OozinozFilter extends FilterWriter • {• protected OozinozFilter(Writer out) • {• super(out);• }

• public void write(char cbuf[], int offset, int length) throws IOException • {• for (int i = 0; i < length; i++) • write(cbuf[offset + i]);• }

• public abstract void write(int c) throws IOException;

• public void write(String s, int offset, int length) throws IOException • {• write(s.toCharArray(), offset, length);• }• }

Page 32: Unit 13 Decorator

32

• In file I/O there is no effective difference between the char and int types

• In the previous code the first concrete write() method depends on the abstract write() method for its implementation

• This call in the concrete method:• write(cbuf[offset + i]);• Uses this method:• public abstract void write(int c) throws IOException;

Page 33: Unit 13 Decorator

33

• You may already foresee how the subclasses will achieve their goal of different function

• It is the usual trickery based on polymorphism and dynamic binding

• By changing the implementation of the “used” method in the subclass, the function of the method that uses it, inherited from the superclass, will be changed

Page 34: Unit 13 Decorator

34

• The second concrete method in the subclass takes a String as a parameter

• When writing the string, it makes this call:• write(s.toCharArray(), offset, length);

• In other words, it makes use of the other concrete method

• Therefore, the results of this method ultimately rely on the implementation of the abstract write() method too

Page 35: Unit 13 Decorator

35

• The overall end result is this:• You can call any of the write() methods on an

instance of one of the filter classes• When you do so, whatever formatting was in the

simple write() method that had to be implemented in the subclass will apply to all of the write() methods

• The code for the concrete, LowerCaseFilter class is shown on the next overhead

Page 36: Unit 13 Decorator

36

• public class LowerCaseFilter extends OozinozFilter • {• public LowerCaseFilter(Writer out) • {• super(out);• }

• public void write(int c) throws IOException • {• out.write(Character.toLowerCase((char) c));• }• }

Page 37: Unit 13 Decorator

37

• Calling a write() method on an instance of this class changes all text to lower case

• The implementation is not difficult• You don’t even have to do anything like add or

subtract Unicode values• You get to rely on a method that already exists

in the Character class

Page 38: Unit 13 Decorator

38

• On the next overhead an example program is given which uses the LowerCaseFilter

• This program doesn’t write to a file• Instead, it writes to the console, but this makes

no difference• The code illustrates nested construction, or

composition• It will output the String with the strange

capitalization in all small letters

Page 39: Unit 13 Decorator

39

• public class ShowLowerCase • {• public static void main(String[] args) throws IOException • {• Writer out = new ConsoleWriter();• out = new LowerCaseFilter(out);• out.write("This Text, notably ALL in LoWeR casE!");• out.close(); • }• }

Page 40: Unit 13 Decorator

40

• For better or worse, it has to be noted that the ConsoleWriter class used in the previous example is not a class in the Java API

• It doesn’t exist yet…• At the end of this section the book gives the

writing of such a class as a challenge• (You may observe that it would be sort of a

relative of MyTerminalIO)

Page 41: Unit 13 Decorator

41

• The UpperCaseFilter class works the same was as the LowerCaseFilter class

• The only difference is a minor one in the implementation of the write() method, which is shown below

• public void write(int c) throws IOException • {• out.write(Character.toUpperCase((char) c));• }

Page 42: Unit 13 Decorator

42

• Next the book gives the TitleCaseFilter class• It capitalizes every word in a string which

follows white space• It would be considerably more complicated if

you tried to follow the real rules for capitalizing titles

• The code is given on the next overhead

Page 43: Unit 13 Decorator

43

• public class TitleCaseFilter extends OozinozFilter • {• boolean inWhite = true;

• public TitleCaseFilter(Writer out) • {• super(out);• }

• public void write(int c) throws IOException • {• out.write(inWhite ? Character.toUpperCase((char) c) :

Character.toLowerCase((char) c));• inWhite = Character.isWhitespace((char) c) || c == '"';• }• }

Page 44: Unit 13 Decorator

44

• Next the book gives the CommaListFilter class• It puts a comma and a space after every item

that’s written• It would be considerably more complicated if

you tried to insert commas between any words separated by white space in the String to be written

• The code is given on the next overhead

Page 45: Unit 13 Decorator

45

• public class CommaListFilter extends OozinozFilter • {• protected boolean needComma = false;

• public CommaListFilter(Writer writer) • {• super(writer);• }

• public void write(int c) throws IOException • {• if (needComma) • {• out.write(',');• out.write(' ');• }• out.write(c);• needComma = true;• }

• public void write(String s) throws IOException • {• if (needComma)• out.write(", ");

• out.write(s);• needComma = true;• }• }

Page 46: Unit 13 Decorator

46

• Keep in mind that the general plan of the filter classes is the same

• They take a parameter to be written and they “decorate” it or modify it in some way before writing it out

• The LowerCaseFilter, UpperCaseFilter, and TitleCaseFilter classes changed the characters

• The CommaListFilter added characters to the output

Page 47: Unit 13 Decorator

47

• Challenge 27.1• Write the code for RandomCaseFilter.java.

Page 48: Unit 13 Decorator

48

• Solution 27.1• One solution is:• [See the next overhead.]

Page 49: Unit 13 Decorator

49

• public class RandomCaseFilter extends OozinozFilter • {• public RandomCaseFilter(Writer out) • {• super(out);• }

• public void write(int c) throws IOException • {• out.write(Math.random() < .5 ?

Character.toLowerCase((char) c)• : Character.toUpperCase((char) c));• }• }

Page 50: Unit 13 Decorator

50

• Next the book mentions the WrapFilter class• It takes as an input parameter both a Writer

and a line length• It has the effect of eating up unnecessary

white space and adding enough at the beginning of a line of text to center it

• The book doesn’t bother to give the code because it is too long and complex

Page 51: Unit 13 Decorator

51

• Next the book gives another example program, ShowFilters, which illustrates how various different filter behaviors can be composed together with nested construction

• It shows nested construction three levels deep• The code for this example is given on the next

overhead

Page 52: Unit 13 Decorator

52

• public class ShowFilters • {• public static void main(String args[]) throws IOException • {• BufferedReader in = new BufferedReader(new FileReader(args[0]));• Writer out = new FileWriter(args[1]);• out = new WrapFilter(new BufferedWriter(out), 40);• out = new TitleCaseFilter(out);

• String line;• while ((line = in.readLine()) != null)• out.write(line + "\n");• • out.close();• in.close();• }• }

Page 53: Unit 13 Decorator

53

• The book shows sample input and output for the program

• I don’t see any reason to reproduce that here• Next the book turns to the question of output

to the screen instead of a file• That is tangential to the topic of the Decorator

design pattern and will also not be covered

Page 54: Unit 13 Decorator

54

• How the decorator pattern works will be addressed one more time

• The picture on the next overhead graphically illustrates the idea of nested construction

• The first filter object contains an instance of writer

• Every filter object after that contains an instance of filter, which potentially wraps another instance of filter, and so on

Page 55: Unit 13 Decorator

55

Page 56: Unit 13 Decorator

56

• The question was raised earlier, what do you gain by using this pattern rather than making a hierarchy of subclasses

• Consider the UML diagram, which is repeated on the next overhead

• All of the concrete filter classes are siblings• The “hierarchy” is flat

Page 57: Unit 13 Decorator

57

Page 58: Unit 13 Decorator

58

• What you gain with the pattern is complete freedom in composing behaviors

• Each one of the siblings can “eat” one of the other siblings

• You can have a chain of wrapped filters including as many or as few as you want

Page 59: Unit 13 Decorator

59

• This leads back to the question of how it works again

• The fundamental idea given earlier was that you override a basic method which an inherited method calls

• However, there is another equally important element to this

Page 60: Unit 13 Decorator

60

• The method you override is recursive• Look at the code for the LowerCaseFilter

write() method again for example:

• public void write(int c) throws IOException • {• out.write(Character.toLowerCase((char) c));• }

Page 61: Unit 13 Decorator

61

• It is recursive• It’s not recursive in the traditional sense, but it’s

still recursive• The write() method is defined in terms of the

write() method for the filter/writer object that this object contains

• Calling write() triggers nested calls to each successive contained object, using the write method for that object

Page 62: Unit 13 Decorator

62

• This is how behaviors or functionalities are composed using the pattern

• Each individual write() method filters, or transforms the output in some way

• The end result is that the output reflects each of the transformations of the write() methods included by the original nested construction

Page 63: Unit 13 Decorator

63

• There is one more piece of this that has to be explained

• The write() method has to be implemented in the classes because it’s abstract in the superclass

• However, the implementation of the write() method contains a call to write()

Page 64: Unit 13 Decorator

64

• When you reach “the end of the recursion”, where does the last implementation of write() come from?

• The answer is that at the end of the recursion, the contained object is the original writer, not a filter

• The write() method exists in the Writer class, and polymorphism calls that version of the method

Page 65: Unit 13 Decorator

65

• The hidden structure of the pattern as given includes this blip:

• The superclass, Writer, has a write() method• The abstract class FilterWriter, a subclass of

Writer, has an abstract method write()• This means that the concrete filter classes do not

inherit write(), but have to implement, even though a valid write() method does exist 2 levels above them in the hierarchy

Page 66: Unit 13 Decorator

66

Another Example

• This next example illustrates decoration by composing behaviors for graphical output

• These are the basic classes of the example:• ColorEllipse.java, EllipsePainter.java• ColorEllipse is the thing that’s graphically

represented• EllipsePainter plays the role of the writer in

the previous example

Page 67: Unit 13 Decorator

67

• There are 8 decorator classes• The first 3 are fully explained• The rest are analogous to the first 3

Page 68: Unit 13 Decorator

68

• DoubleMajorEllipsePainter.java: Given a color ellipse, this finds the major (longer) axis and doubles it. If the ellipse is a circle, then both axes are doubled. If not, the minor axis is not changed.

• MoveRightEllipsePainter.java: Given a color ellipse, this moves the location of the ellipse to the right by adding 200 to the x coordinate of its bounding box.

• ShiftRedEllipsePainter.java: Given a color ellipse, this increments the red component of its color by the value 85, mod 256.

Page 69: Unit 13 Decorator

69

• The additional decorator classes:• DoubleMinorEllipsePainter• HalveMajorEllipsePainter• HalveMinorEllipsePainter• MoveLeftEllipsePainter• MoveUpEllipsePainter• MoveDownEllipsePainter• ShiftGreenEllipsePainter• ShiftBlueEllipsePainter

Page 70: Unit 13 Decorator

70

• The screenshot on the following overhead shows the output of a test program

• The test program is outlined after that• Following that, the code is described

Page 71: Unit 13 Decorator

71

Page 72: Unit 13 Decorator

72

How the Ellipses are Generated in the Test Program Output

• 1. Upper Left Ellipse• A. Create a plain EllipsePainter.• B. Paint myEllipse using the latest ellipse painter.• 2. Upper Right Ellipse• A. Create a MoveRightEllipsePainter using the previous painter

as a parameter.• B. Create a DoubleMajor EllipsePainter using the previous

painter as a parameter.• C. Create a ShiftRedEllipsePainter using the previous painter as

a parameter.• D. Paint myEllipse using the latest ellipse painter.

Page 73: Unit 13 Decorator

73

• 3. Lower Left Ellipse• A. Create an ellipse painter using the previous painter as a parameter. This ellipse painter should counteract

the move right that is part of the previous ellipse painter.• B. Create an ellipse painter using the previous painter as a parameter. This ellipse painter should counteract

the double major that is part of the previous ellipse painter.• C. Create an ellipse painter using the previous painter as a parameter This ellipse painter should cause the

ellipse to be moved down.• D. Create an ellipse painter using the previous painter as a parameter. This ellipse painter should cause the

minor axis of the ellipse to be half as wide.• E. Create an ellipse painter using the previous painter as a parameter. This ellipse painter should cause a blue

shift in the ellipse's color.• F. Paint myEllipse using the latest ellipse painter.• 4. Lower Right Ellipse• A. Create an ellipse painter using the previous painter as a parameter. This ellipse painter should counteract

the move down that is part of the previous ellipse painter.• B. Create an ellipse painter using the previous painter as a parameter. This ellipse painter should counteract

the halving of the minor axis that is part of the previous ellipse painter.• C. Create an ellipse painter using the previous painter as a parameter. This ellipse painter should cause the

ellipse to be moved to the left.• D. Create an ellipse painter using the previous painter as a parameter. This ellipse painter should cause the

major axis of the ellipse to be half as wide.• E. Create an ellipse painter using the previous painter as a parameter. This ellipse painter should cause a

green shift in the ellipse's color.• F. Paint myEllipse using the latest ellipse painter.

Page 74: Unit 13 Decorator

74

• A subset of the code for the ColorEllipse class is given on the following overheads

• The code for altering ellipses is packaged in the ColorEllipse class

• Only the code needed for the first three decorators is given

Page 75: Unit 13 Decorator

75

• import java.awt.*;• import java.awt.geom.*;• import java.awt.event.*;• import javax.swing.*;• import java.lang.*;• import java.util.*;

• public class ColorEllipse• {• private Ellipse2D.Double ellipseShape;• private Color ellipseColor;

• public ColorEllipse(Ellipse2D.Double ellipseShapeIn, Color ellipseColorIn)• {• ellipseShape = ellipseShapeIn;• ellipseColor = ellipseColorIn;• }

• public Ellipse2D.Double getEllipseShape()• {• return ellipseShape;• }

• public Color getEllipseColor()• {• return ellipseColor;• }

Page 76: Unit 13 Decorator

76

• public void doubleMajor()• {• if(ellipseShape.getWidth() > ellipseShape.getHeight())• {• ellipseShape = new Ellipse2D.Double(ellipseShape.getX(),

ellipseShape.getY(), 2 * ellipseShape.getWidth(), ellipseShape.getHeight());• }• else if(ellipseShape.getHeight() > ellipseShape.getWidth())• {• ellipseShape = new Ellipse2D.Double(ellipseShape.getX(),

ellipseShape.getY(), ellipseShape.getWidth(), 2 * ellipseShape.getHeight());• }• else• {• ellipseShape = new Ellipse2D.Double(ellipseShape.getX(),

ellipseShape.getY(), 2 * ellipseShape.getWidth(), 2 * ellipseShape.getHeight());

• }• }

Page 77: Unit 13 Decorator

77

• public void shiftRed()• {• ellipseColor = new Color((ellipseColor.getRed() + 85) %

256, ellipseColor.getGreen(), ellipseColor.getBlue());• }

• public void moveRight()• {• ellipseShape = new Ellipse2D.Double(ellipseShape.getX()

+ 200, ellipseShape.getY(), ellipseShape.getWidth(), ellipseShape.getHeight());

• }

• }

Page 78: Unit 13 Decorator

78

• The code for the EllipsePainter class is given on the overhead following the next one

• This is the superclass for all of the other painters (decorators)

• This class is not abstract• This makes it possible to display an ellipse

without decorations

Page 79: Unit 13 Decorator

79

• Also, this is one of the rare occasions when you will see me use a protected access modifier

• The graphics parameter in the EllipsePainter superclass, g2, is inherited by the subclass filter/decorator/painter subclasses

• It is made directly available to them by declaring g2 protected so that it isn’t necessary to call get() methods on the g2 parameter in the subclass code

Page 80: Unit 13 Decorator

80

• import java.awt.*;• import java.awt.geom.*;• import java.awt.event.*;• import javax.swing.*;• import java.lang.*;• import java.util.*;

• public class EllipsePainter• {• protected Graphics2D g2;

• public EllipsePainter(Graphics2D g2In)• {• g2 = g2In;• }

• public void paintEllipse(ColorEllipse ellipseIn)• {• g2.setColor(ellipseIn.getEllipseColor());• g2.fill(ellipseIn.getEllipseShape());• }• }

Page 81: Unit 13 Decorator

81

• The code for the three individual filter/decorator/painter classes is given on the following overheads

Page 82: Unit 13 Decorator

82

• import java.awt.*;• import java.awt.geom.*;• import java.awt.*;• import java.awt.geom.*;• import java.awt.event.*;• import javax.swing.*;• import java.lang.*;• import java.util.*;

• public class DoubleMajorEllipsePainter extends EllipsePainter• {• private EllipsePainter ePainter;

• public DoubleMajorEllipsePainter(EllipsePainter ellipsePainterIn)• {• super(ellipsePainterIn.g2);• ePainter = ellipsePainterIn;• }

• public void paintEllipse(ColorEllipse ellipseIn)• {• ellipseIn.doubleMajor();• ePainter.paintEllipse(ellipseIn);• }• }

Page 83: Unit 13 Decorator

83

• import java.awt.*;• import java.awt.geom.*;• import java.awt.*;• import java.awt.geom.*;• import java.awt.event.*;• import javax.swing.*;• import java.lang.*;• import java.util.*;

• public class MoveRightEllipsePainter extends EllipsePainter• {• private EllipsePainter ePainter;

• public MoveRightEllipsePainter(EllipsePainter ellipsePainterIn)• {• super(ellipsePainterIn.g2);• ePainter = ellipsePainterIn;• }

• public void paintEllipse(ColorEllipse ellipseIn)• {• ellipseIn.moveRight();• ePainter.paintEllipse(ellipseIn);• }• }

Page 84: Unit 13 Decorator

84

• import java.awt.*;• import java.awt.geom.*;• import java.awt.*;• import java.awt.geom.*;• import java.awt.event.*;• import javax.swing.*;• import java.lang.*;• import java.util.*;

• public class ShiftRedEllipsePainter extends EllipsePainter• {• private EllipsePainter ePainter;

• public ShiftRedEllipsePainter(EllipsePainter ellipsePainterIn)• {• super(ellipsePainterIn.g2);• ePainter = ellipsePainterIn;• }

• public void paintEllipse(ColorEllipse ellipseIn)• {• ellipseIn.shiftRed();• ePainter.paintEllipse(ellipseIn);• }• }

Page 85: Unit 13 Decorator

85

UML for the Pattern

• A simplified schematic for the book’s illustration of the pattern is given on the next overhead

• This shows an abstract class

Page 86: Unit 13 Decorator

86

Page 87: Unit 13 Decorator

87

• A simplified schematic for the other example of the pattern is given on the next overhead

• It is simpler because it doesn’t have an abstract class

• Each subclass is shown individually with a reference to a superclass type

Page 88: Unit 13 Decorator

88

Page 89: Unit 13 Decorator

89

Lasater’s UML Diagram for the Pattern

• Lasater’s UML diagram is shown on the overhead following the next one

• Lasater includes the abstract class as part of the pattern

• He also tries to indicate the methods (operations) and how they’re part of the pattern

• It’s useful to see the superclass generically referred to as a component—not spefically a filter or painter

Page 90: Unit 13 Decorator

90

• In general, some component will have decorator subclasses

• Notice that Lasater shows the Component class having a ConcreteComponent subclass as well as a Decorator subclass

• This leads to a cosmic question that won’t be pursued any further:

• Is the decorator subclass an “improper” subclass—that is, a subclass that “is not a kind of” its superclass?

Page 91: Unit 13 Decorator

91

Page 92: Unit 13 Decorator

92

• Keep in mind that the UML can’t quite capture the pattern fully

• It can make it clear that you need to implement a method in the subclasses if there is an abstract method in the abstract superclass

• Or it can make it clear that you’re overriding the method in the subclasses if the superclass is concrete

Page 93: Unit 13 Decorator

93

• However, a UML diagram doesn’t typically show the bodies of methods

• Without lots of comments, the UML diagram doesn’t show these two things:

• 1. How a method inherited from the superclass depends on the method implemented/overridden in the subclass

Page 94: Unit 13 Decorator

94

• 2. How the overridden method is “dynamic binding recursive”

• Its implementation contains a call to a method of the same name on the wrapped object

• It depends on inheriting an existing implementation of a method of that name from a superclass above the abstract class—or from the immediate superclass if it’s concrete

• And it then depends on the existence of the method in all of the subclasses

Page 95: Unit 13 Decorator

95

Summary

• The Decorator design pattern lets you mix together variations of an operation

• Input and output streams illustrate the pattern and illustrate the composition of behaviors with nested construction

• Not only is Java set up in this way, it allows you to create your own I/O (filter) classes that are based on the decoration idea

• The Decoration pattern can also be applied in other problem domains

Page 96: Unit 13 Decorator

96

The End

Page 97: Unit 13 Decorator

97

• However, it was used in one of the earlier examples

• So for the sake of completeness it will be covered

• The book shows where the ConsoleWriter class would fit into the hierarchy in the UML diagram given on the next overhead

Page 98: Unit 13 Decorator

98

Page 99: Unit 13 Decorator

99

• Challenge 27.2• Write the code for ConsoleWriter.java• Comment mode on:• You have seen programmer written code which served a

similar, but more general purpose before:• MyTerminalIO• The details of the code are not of particular interest• It is assumed that if it’s not totally transparent, it would

be easy enough to figure out how it worked by referring to the Java API

Page 100: Unit 13 Decorator

100

• Solution 27.2• One solution is:• [See the following overhead.]

Page 101: Unit 13 Decorator

101

• public class ConsoleWriter extends Writer • {• public void close() {}• public void flush() {}• • public void write(char[] buffer, int offset, int length) • {• for (int i = 0; i < length; i++) • System.out.print(buffer[offset + i]);• }• }

Page 102: Unit 13 Decorator

102

• The diagrams for the second half of the chapter are tipped in here for future reference

• You don’t have to worry about them because the second half wasn’t covered in class and you’re not responsible for it

Page 103: Unit 13 Decorator

103

Page 104: Unit 13 Decorator

104

Page 105: Unit 13 Decorator

105

Page 106: Unit 13 Decorator

106

Page 107: Unit 13 Decorator

107