unit 13 decorator summary prepared by kirk scott 1

122
Unit 13 Decorator Summary prepared by Kirk Scott 1

Upload: norma-davidson

Post on 17-Dec-2015

219 views

Category:

Documents


1 download

TRANSCRIPT

Page 1: Unit 13 Decorator Summary prepared by Kirk Scott 1

1

Unit 13Decorator

Summary prepared by Kirk Scott

Page 3: Unit 13 Decorator Summary prepared by Kirk Scott 1

3

Page 4: Unit 13 Decorator Summary prepared by Kirk Scott 1

4

Page 5: Unit 13 Decorator Summary prepared by Kirk Scott 1

5

Design Patterns in JavaChapter 27Decorator

Summary prepared by Kirk Scott

Page 6: Unit 13 Decorator Summary prepared by Kirk Scott 1

6

Page 7: Unit 13 Decorator Summary prepared by Kirk Scott 1

7

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 8: Unit 13 Decorator Summary prepared by Kirk Scott 1

8

• 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 9: Unit 13 Decorator Summary prepared by Kirk Scott 1

9

• The book 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

• There will be another example that does not come from the book

Page 10: Unit 13 Decorator Summary prepared by Kirk Scott 1

10

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

• When you think of adding functionality to an application you usually think of adding new classes or new methods to existing classes

• The Decorator design pattern is a model for adding functionality to a code base in a way that leads to a specific result

Page 11: Unit 13 Decorator Summary prepared by Kirk Scott 1

11

• A certain set of methods/functionality will exist in various classes in the code base

• If the pattern is used, there will be flexibility in making objects that have differing subsets of the existing functionality

• At run time a program can varying sequences of construction to create objects that have differing functionality in them

Page 12: Unit 13 Decorator Summary prepared by Kirk Scott 1

12

Book Definition of Pattern

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

new variations of an operation at runtime.

Page 13: Unit 13 Decorator Summary prepared by Kirk Scott 1

13

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 14: Unit 13 Decorator Summary prepared by Kirk Scott 1

14

• 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 15: Unit 13 Decorator Summary prepared by Kirk Scott 1

15

• 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 16: Unit 13 Decorator Summary prepared by Kirk Scott 1

16

• This example illustrates nested construction• A FileWriter is constructed• It is then passed as a construction parameter

when the BufferedWriter is constructed• The BufferedWriter can have FileWriter

functionality since it contains a reference to FileWriter

• The BufferedWriter can also add new functionality

Page 17: Unit 13 Decorator Summary prepared by Kirk Scott 1

17

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

• The decorator pattern/nested construction opens up the possibility of overloading

• This overloading can be accomplished by wrapping calls to a method of the same name on the object sent in at construction time and adding code around the calls

Page 18: Unit 13 Decorator Summary prepared by Kirk Scott 1

18

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

• The point is that the write() method of BufferedWriter will have different functionality and calling it will give different results from calling write() on a FileWriter object

• The BufferedWriter could also have entirely different methods with different functionality

Page 19: Unit 13 Decorator Summary prepared by Kirk Scott 1

19

• The PrintWriter class provides a simple, concrete 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 the methods print() and println() in addition to write(), which it shares with FileWriter

Page 20: Unit 13 Decorator Summary prepared by Kirk Scott 1

20

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

• So using the decorator pattern, not only can you overload methods;

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

Page 21: Unit 13 Decorator Summary prepared by Kirk Scott 1

21

Applying the Pattern with Writers

• 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 text upper case or lower case

Page 22: Unit 13 Decorator Summary prepared by Kirk Scott 1

22

• The book refers to these formatting classes as filter classes

• Generically they might be referred to as decorator classes

• The book 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 23: Unit 13 Decorator Summary prepared by Kirk Scott 1

23

Page 24: Unit 13 Decorator Summary prepared by Kirk Scott 1

24

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

• FilterWriter extends Writer• FilterWriter also contains an instance of Writer

Page 25: Unit 13 Decorator Summary prepared by Kirk Scott 1

25

• This illustrates the basic plan• A FilterWriter wraps an instance of its

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

• A programmer can apply the pattern by extending the FilterWriter class

• Structurally, the idea of a class with a reference to its superclass is already built into the Java API

Page 26: Unit 13 Decorator Summary prepared by Kirk Scott 1

26

The Decorator and Proxy Patterns

• You may recall that having a reference to a superclass object 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

Page 27: Unit 13 Decorator Summary prepared by Kirk Scott 1

27

• Because the structure is built into the Java API for writers, there is no avoiding it here

• The Java API developers decided that this was the right structure for implementing the kind of flexible functionality that they wanted for writers

• The question of the desirability of this structure will come up again when discussing the advantages of this pattern

Page 28: Unit 13 Decorator Summary prepared by Kirk Scott 1

28

Java API Documentation of the Class FilterWriter

• 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 29: Unit 13 Decorator Summary prepared by Kirk Scott 1

29

FilterWriter API Documentation Snippet

• 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 30: Unit 13 Decorator Summary prepared by Kirk Scott 1

30

Putting the OozinozFilter Class into the Hierarchy

• 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

• The user extends the FilterWriter class and works with the wrapped Writer

• The OozinozFilter class is abstract, so concrete subclasses of it will be needed

Page 31: Unit 13 Decorator Summary prepared by Kirk Scott 1

31

Page 32: Unit 13 Decorator Summary prepared by Kirk Scott 1

32

Adding Concrete Subclasses

• Next, the book extends its example UML diagram

• This 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 33: Unit 13 Decorator Summary prepared by Kirk Scott 1

33

• The diagram also shows the OozinozFilter class’s 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 34: Unit 13 Decorator Summary prepared by Kirk Scott 1

34

Page 35: Unit 13 Decorator Summary prepared by Kirk Scott 1

35

• 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 learned that you can pass in a subclass object for a superclass formal parameter

Page 36: Unit 13 Decorator Summary prepared by Kirk Scott 1

36

Implementing the Abstract Method in the Subclasses

• OozinozFilter has an abstract write() method• This write() method takes a single int at a time

as its input parameter, representing a character• The concrete, filter subclasses will have to

implement this method• The filter classes are going to do their work,

and differ, according to their implementation of that method

Page 37: Unit 13 Decorator Summary prepared by Kirk Scott 1

37

• The OozinozFilter class also has two concrete write() methods

• The filter subclasses may simply inherit the write() methods

• They may override them• They may also overload write()

Page 38: Unit 13 Decorator Summary prepared by Kirk Scott 1

38

Code for the OozinozFilter Class

• The code for the OozinozFilter class will be given on the overhead following the next one

• It shows the declaration of the abstract write() method

• It also shows the implementations of two concrete write() methods

Page 39: Unit 13 Decorator Summary prepared by Kirk Scott 1

39

• When looking at the code, note the following:• The first concrete write() method depends on

the abstract method• The second concrete write() method depends

on the first concrete method

Page 40: Unit 13 Decorator Summary prepared by Kirk Scott 1

40

• Much of the remaining explanation of how the pattern works will have to do with how method implementations depend on each other

• In other words, understanding the pattern doesn’t just mean understanding nested construction

• It means understanding how the methods are implemented

Page 41: Unit 13 Decorator Summary prepared by Kirk Scott 1

41

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

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

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

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

Page 42: Unit 13 Decorator Summary prepared by Kirk Scott 1

42

A Syntactical Note

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

• That means that you have a formal parameter of the one type and you can pass an actual parameter of the other type

Page 43: Unit 13 Decorator Summary prepared by Kirk Scott 1

43

The First Concrete Method Depends on the Abstract Method

• The first concrete write() method in OozinozFilter depends on the abstract write() method for its implementation

• This is the call wrapped in the first concrete method:

• write(cbuf[offset + i]);• That call is making use of this method:• public abstract void write(int c) throws IOException;

Page 44: Unit 13 Decorator Summary prepared by Kirk Scott 1

44

The Second Concrete Method Depends on the First Concrete Method

• The second concrete method in OozinozFilter takes a String as a parameter

• This is the call wrapped in the second concrete method:

• write(s.toCharArray(), offset, length);

• It converts the string parameter to an array of characters and uses the first concrete method

• Therefore, the second concrete method ultimately relies on the abstract write() method too

Page 45: Unit 13 Decorator Summary prepared by Kirk Scott 1

45

Polymorphism and Dynamic Binding Trickery

• The next couple of overheads will try to explain verbally how you get various versions of write in your subclasses

• Let the scenario be trimmed down to one abstract superclass and one concrete subclass

• Let the abstract superclass contain an abstract method

• Let the abstract superclass also contain one concrete method that wraps a call to the abstract method

Page 46: Unit 13 Decorator Summary prepared by Kirk Scott 1

46

• You can’t call either method on an instance of the abstract class

• There can’t be an instance of an abstract class• Both methods in the superclass affect the

subclass• The subclass has to implement the abstract

method• The subclass will inherit the concrete method

Page 47: Unit 13 Decorator Summary prepared by Kirk Scott 1

47

• So the subclass has a concrete implementation of the abstract method declared in the superclass

• Suppose you call the inherited concrete method on a subclass object

• When the code for that method is run, you encounter a call to the abstract method

• Dynamic binding says that the version of the method defined in the subclass should be used

Page 48: Unit 13 Decorator Summary prepared by Kirk Scott 1

48

An Example of a Filter

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

• In it, the abstract method is implemented to change every character to lower case on output

• As a result, when any write() method is called on a LowerCaseFilter object, the output will be in lowercase

Page 49: Unit 13 Decorator Summary prepared by Kirk Scott 1

49

• This happens directly if the simple write() method is called

• Conversion to lowercase happens indirectly if either of the two inherited write() methods are called, since they ultimately depend on the implementation of simple write() in LowerCaseFilter

• The code uses the toLowerCase() method in the Java Character class so it’s not necessary to manipulate Unicode values to get lower case

Page 50: Unit 13 Decorator Summary prepared by Kirk Scott 1

50

• 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 51: Unit 13 Decorator Summary prepared by Kirk Scott 1

51

The Writer Has Protected Access

• Notice that in the implementation of write(), you call the inherited write() method on the object out

• This is an instance variable inherited from the Java FilterWriter class

• It is declared protected in the FilterWriter class, so subclasses have direct access to it

Page 52: Unit 13 Decorator Summary prepared by Kirk Scott 1

52

• I am critical of the authors when they use this technique

• Here, it is built into the Java API in order to make it easier for the programmer to use the decorator pattern to make new writers

• It is less messy than writing something like getOut().write()

• Protected access has its uses, but it should probably be used sparingly

Page 53: Unit 13 Decorator Summary prepared by Kirk Scott 1

53

An Example of Nested Construction with a Filter

• On the overhead following the next one an example illustrating nested construction is given

• A ConsoleWriter, which writes to the console rather than a file, is constructed

• It is passed as a construction parameter to the LowerCaseFilter

Page 54: Unit 13 Decorator Summary prepared by Kirk Scott 1

54

• When write() is called on the LowerCaseFilter, the output String with the strange capitalization will go to the console and it will be converted to lowercase

• The point is that the LowerCaseFilter object contains the console output functionality because it was constructed containing such an object

• If the LowerCaseFilter were constructed with a file writer, the lower case output would go to a file instead

Page 55: Unit 13 Decorator Summary prepared by Kirk Scott 1

55

• 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 56: Unit 13 Decorator Summary prepared by Kirk Scott 1

56

• 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 57: Unit 13 Decorator Summary prepared by Kirk Scott 1

57

Another Example of a Filter

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

• The only difference is the call to toUpperCase() 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 58: Unit 13 Decorator Summary prepared by Kirk Scott 1

58

Yet Another Example of a Filter

• 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 59: Unit 13 Decorator Summary prepared by Kirk Scott 1

59

• 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 60: Unit 13 Decorator Summary prepared by Kirk Scott 1

60

Yet Another Example of a Filter

• 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 61: Unit 13 Decorator Summary prepared by Kirk Scott 1

61

• 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 62: Unit 13 Decorator Summary prepared by Kirk Scott 1

62

The Filters Overall

• 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 63: Unit 13 Decorator Summary prepared by Kirk Scott 1

63

• The write() methods in the filter classes are structured pretty much the same way

• They call an inherited write() method on out• out is the reference to the writer inherited

from the superclass

Page 64: Unit 13 Decorator Summary prepared by Kirk Scott 1

64

• The inherited write() method will decorate according to the concrete, local version of the abstract write() method was implemented

• That concrete write() method will add its own decoration

• How many and which different functionalities you get depends on how many levels of nesting and which classes were used in the construction of the ultimate object that write() is being called on

Page 65: Unit 13 Decorator Summary prepared by Kirk Scott 1

65

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

Page 66: Unit 13 Decorator Summary prepared by Kirk Scott 1

66

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

Page 67: Unit 13 Decorator Summary prepared by Kirk Scott 1

67

• 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 68: Unit 13 Decorator Summary prepared by Kirk Scott 1

68

Yet Another Example of a Filter

• 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 69: Unit 13 Decorator Summary prepared by Kirk Scott 1

69

Another Example of Nested Construction with Filters

• 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 four levels deep• Any input to the program would be output with all

of the characteristics defined in each of the writers• The code for this example is given on the next

overhead

Page 70: Unit 13 Decorator Summary prepared by Kirk Scott 1

70

• 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 BufferedWriter(out);• out = new WrapFilter(out, 40);• out = new TitleCaseFilter(out);

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

Page 71: Unit 13 Decorator Summary prepared by Kirk Scott 1

71

Output to the Console

• The book gives the writing of the ConsoleWriter class as a challenge

• The ConsoleWriter is tangential to the discussion of the decorator design pattern

• This part of the book will be skipped

Page 72: Unit 13 Decorator Summary prepared by Kirk Scott 1

72

How the Decorator Pattern Works

• 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 73: Unit 13 Decorator Summary prepared by Kirk Scott 1

73

Page 74: Unit 13 Decorator Summary prepared by Kirk Scott 1

74

• Here is an invented phrase that is supposed to illustrate the sequence of method calls:

• Horizontal recursion• The concrete filter classes are all at the same level in

the hierarchy• At execution time there is a sequence of calls to

methods of the same name• Because each class wraps an instance of a sibling

class, the calls go sideways rather than up and down

Page 75: Unit 13 Decorator Summary prepared by Kirk Scott 1

75

Advantages of the Decorator Pattern

• What do you gain by using a pattern where subclasses contain references to an instance of a superclass?

• One alternative would be a hierarchy of subclasses without superclass instance variables

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

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

Page 76: Unit 13 Decorator Summary prepared by Kirk Scott 1

76

Page 77: Unit 13 Decorator Summary prepared by Kirk Scott 1

77

• The advantage of 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 78: Unit 13 Decorator Summary prepared by Kirk Scott 1

78

How It Works, Again

• This leads back to the question of how the pattern works

• The fundamental idea explained at the beginning was that you override a basic method which an inherited method calls

• If you do nested construction, the write() method of each level depends on the write() method of the level that contains it

Page 79: Unit 13 Decorator Summary prepared by Kirk Scott 1

79

• 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 80: Unit 13 Decorator Summary prepared by Kirk Scott 1

80

• In a sense you could say that the call to write() is recursive

• Nested construction makes nested writer objects

• Calling write() on the ultimate object triggers nested calls to the write() method defined in each successive containing object

Page 81: Unit 13 Decorator Summary prepared by Kirk Scott 1

81

• 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 82: Unit 13 Decorator Summary prepared by Kirk Scott 1

82

Where Does the Sequence of Calls to write() End?

• The write() method is implemented in the concrete filter subclasses because it’s abstract in the filter superclass

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

• This obviously doesn’t come from the abstract class

Page 83: Unit 13 Decorator Summary prepared by Kirk Scott 1

83

• It comes from the original writer, which the nested construction of filters wraps

• The write() method exists in the Writer class• When the end of the wrapped write() calls is

reached, the write() method of the Writer class is called on the wrapped Writer object

Page 84: Unit 13 Decorator Summary prepared by Kirk Scott 1

84

Considering Abstract Classes

• There is a little reminder of how abstract classes work lurking in this example

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

Writer, has an abstract method write()

Page 85: Unit 13 Decorator Summary prepared by Kirk Scott 1

85

• The concrete filter classes are subclasses of the abstract filter class

• Because they have an abstract class above them, they do not inherit write()

• They have to implement that abstract method• All the while, there is a valid write() method 2

levels above them in the hierarchy

Page 86: Unit 13 Decorator Summary prepared by Kirk Scott 1

86

Function Wrappers—Skip

• The second half of the chapter in the book is based on an example of wrapping functions

• This will not be covered• It should be more useful to consider the other

example, which follows

Page 87: Unit 13 Decorator Summary prepared by Kirk Scott 1

87

Another Example

• The other example for this unit is not based on cups and seeds

• It is a relatively straightforward attempt to adapt the book’s ideas to an example that generates output

• Instead of doing text output, it does graphical output of geometric shapes

Page 88: Unit 13 Decorator Summary prepared by Kirk Scott 1

88

• 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 89: Unit 13 Decorator Summary prepared by Kirk Scott 1

89

Output from the Example

• On the following overhead, output from a sample program is shown

• In simple terms, the sample program just creates one ellipse

• The four different appearing ellipses in the output are generated by doing the output of the one ellipse through different decorators

• It is evident that the display size, shape, color, and location of the ellipse are determined by the decorators

Page 90: Unit 13 Decorator Summary prepared by Kirk Scott 1

90

Page 91: Unit 13 Decorator Summary prepared by Kirk Scott 1

91

UML for the Example

• A simplified schematic for the decorators in this example is given on the next overhead

• This example doesn’t have an abstract class• Each subclass is shown individually with a

reference to the EllipsePainter superclass• Also, in the diagram, just 3 painters

(decorators) are shown, and they are shown with generic names

Page 92: Unit 13 Decorator Summary prepared by Kirk Scott 1

92

Page 93: Unit 13 Decorator Summary prepared by Kirk Scott 1

93

The Decorators in the Example

• In total, there are 8 decorator classes in the example

• These decorator classes alter the way an ellipse is presented on the screen

• The first 3 decorators are fully explained• The rest are analogous to the first 3

Page 94: Unit 13 Decorator Summary prepared by Kirk Scott 1

94

The First 3 Decorators

• 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

Page 95: Unit 13 Decorator Summary prepared by Kirk Scott 1

95

• 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 96: Unit 13 Decorator Summary prepared by Kirk Scott 1

96

The Rest of the Decorators

• DoubleMinorEllipsePainter• HalveMajorEllipsePainter• HalveMinorEllipsePainter• MoveLeftEllipsePainter• MoveUpEllipsePainter• MoveDownEllipsePainter• ShiftGreenEllipsePainter• ShiftBlueEllipsePainter

Page 97: Unit 13 Decorator Summary prepared by Kirk Scott 1

97

• The screenshot on the following overhead was shown earlier

• It shows the output of a test program• Following the screenshot, the test program

will be described• Following the description, the code will be

given

Page 98: Unit 13 Decorator Summary prepared by Kirk Scott 1

98

Page 99: Unit 13 Decorator Summary prepared by Kirk Scott 1

99

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 100: Unit 13 Decorator Summary prepared by Kirk Scott 1

100

• 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.

Page 101: Unit 13 Decorator Summary prepared by Kirk Scott 1

101

• 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 102: Unit 13 Decorator Summary prepared by Kirk Scott 1

102

ColorEllipse Code

• 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 103: Unit 13 Decorator Summary prepared by Kirk Scott 1

103

• 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 104: Unit 13 Decorator Summary prepared by Kirk Scott 1

104

• 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 105: Unit 13 Decorator Summary prepared by Kirk Scott 1

105

• 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 106: Unit 13 Decorator Summary prepared by Kirk Scott 1

106

EllipsePainter Code

• 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 107: Unit 13 Decorator Summary prepared by Kirk Scott 1

107

• 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 108: Unit 13 Decorator Summary prepared by Kirk Scott 1

108

• 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 109: Unit 13 Decorator Summary prepared by Kirk Scott 1

109

Decorator Code

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

Page 110: Unit 13 Decorator Summary prepared by Kirk Scott 1

110

• 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 111: Unit 13 Decorator Summary prepared by Kirk Scott 1

111

• 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 112: Unit 13 Decorator Summary prepared by Kirk Scott 1

112

• 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 113: Unit 13 Decorator Summary prepared by Kirk Scott 1

113

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 114: Unit 13 Decorator Summary prepared by Kirk Scott 1

114

Page 115: Unit 13 Decorator Summary prepared by Kirk Scott 1

115

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 specifically a filter or painter

Page 116: Unit 13 Decorator Summary prepared by Kirk Scott 1

116

• 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 117: Unit 13 Decorator Summary prepared by Kirk Scott 1

117

Page 118: Unit 13 Decorator Summary prepared by Kirk Scott 1

118

• 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 119: Unit 13 Decorator Summary prepared by Kirk Scott 1

119

• 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 120: Unit 13 Decorator Summary prepared by Kirk Scott 1

120

• 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 121: Unit 13 Decorator Summary prepared by Kirk Scott 1

121

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 122: Unit 13 Decorator Summary prepared by Kirk Scott 1

122

The End