Top Banner
Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1
122

Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

Jan 12, 2016

Download

Documents

Bethany Webster
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

1

Design Patterns in JavaChapter 5Composite

Summary prepared by Kirk Scott

Page 2: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

2

Composites

• Before defining a composite, let a component be defined

• A component is a class or interface which can be– Implemented by a class representing individual

items– Or implemented by a class that represents a

collection of such items

Page 3: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

3

• A composite is a class that contains a collection of components as defined above

• This means that the composite can contain both individual items and collections of such items

• The striking thing that will become apparent about the pattern is that the composite class implements the component interface

• A composite can contain both individual items and other instances of the composite class

Page 4: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

4

• The authors use the terms leaf and group to generically describe these concepts

• The use of the term leaf suggests that in at least some cases this design pattern results in tree-like groups of items

• It is important to note that in this design pattern, so-called leaf items are not restricted to the outermost branches of the tree

Page 5: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

5

• Take a directory structure for example• Any directory can contain individual files as

well as additional directories• This ability to have elements that are either

individual or composite is one of the important design features of the pattern

Page 6: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

6

• The second important design feature is to define behaviors (actions, operations, methods) which can be applied to both individual items and groups

• As will be shown shortly, a component class, a leaf class, and a composite class are integral parts of the Composite design pattern

• It is not the case that the composite class itself embodies the pattern

• Without all three classes you don’t have the Composite design pattern

Page 7: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

7

• As defined by the book, this is the intent of this design pattern:

• The intent of the Composite pattern is to let clients treat individual objects and compositions of objects uniformly

Page 8: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

8

• Notice the appearance of the word client in this definition

• As usual, the design pattern doesn’t exist in isolation

• The design pattern provides a model for making certain capabilities available to user written code

• The following UML diagram illustrates the structure of the Composite design pattern

Page 9: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

9

Page 10: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

10

• At the top of the design pattern is a Component• In the diagram and the following discussion, Component is

implemented as an abstract class, which is perfectly all right

• The Component class could also be implemented as an interface

• In this example there is an advantage to implementing it as an abstract class

• It’s possible to provide some actual method implementations in the abstract class, along with the abstract method specifications

Page 11: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

11

• Either way, the purpose the Component class serves is to provide a generic interface that each of the classes underneath it in the design, the Leaf class and the Composite class, have to conform to

• As stated by the book, the intent of the Composite pattern is to let clients treat individual objects and compositions of objects uniformly

• It is the Component part of the design that defines this uniform interface

Page 12: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

12

• Under the Component are subclasses Leaf and Composite which share the uniform interface

• A leaf is a leaf and there are no further details there except for overriding inherited methods or implementing abstract or interface methods

• The relationship between the Composite class and the Component class is more complex and gives this design pattern its important characteristics

Page 13: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

13

• In the UML diagram the composition symbol is used to signify that an instance of Composite can have instances of Component

• A component can be either a leaf or a composite, so a composite can have either leaves or composites or both

Page 14: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

14

• Notice the appearance, once again, of the concepts of polymorphism and interfaces in this design pattern

• An instance of Composite can have more than one different kind of thing

• What it can have can be defined by an abstract class or an interface

Page 15: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

15

• If what the composite can have is defined by an abstract class, then the composite can have anything that is a subclass of that class

• If what the composite can have is defined by an interface, then the composite can have anything that implements that interface

Page 16: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

16

• The design pattern can be summarized by two observations stemming from the foregoing

• Some kind of leaf class extends/implements the component class/interface which a composite can have

• More importantly, the composite class itself extends/implements the component class/interface which the composite can have

• The UML diagram is repeated below for reference

Page 17: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

17

Page 18: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

18

• Challenge 5.1• Why does the Composite class in Figure 5.1

maintain a collection of Component objects instead of simply a collection of leaves?

Page 19: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

19

• Solution 5.1• Designing the Composite class to maintain a

collection of Component objects lets a Composite object hold either Leaf objects or other Composite objects.

Page 20: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

20

• Solution 5.1, cont’d.• In other words, this design lets us model groups as

collections of other groups. For example, we might want to define a user’s system privileges as a collection of either specific privileges or other groups of privileges. As another example, we might want to be able to define a work process as a collection of process steps and other processes. Such definitions are much more flexible than defining a composite to be a collection of leaves.

Page 21: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

21

• Solution 5.1, cont’d.• If we allowed only collections of leaves, our

“composites” could be only one layer deep.• Commentary mode on:• This last part of the book’s answer raises a question,

which will be stated below, but not pursued• Could you come up with a design pattern that created

multi-layer trees where there were internal nodes and leaf nodes, but only the lowest layer of internal node code have a leaf node?

Page 22: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

22

• Commentary mode cont’d.• Although I’m not suggesting trying to

implement or model a directory structure using the Composite design pattern, I still think it’s the most succinct and familiar example of the pattern

• The pattern also arises in manufacturing (databases) where assemblies consist of parts and subassemblies

Page 23: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

23

Recursive Behavior in Composites

• The book, as usual, has an example from the Oozinoz domain

• Briefly, there are individual machines that are components of the manufacturing process

• These are the leaves

Page 24: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

24

• There are also machines which are compositions of other machines

• These compositions are collectively thought of as single, composite components of the manufacturing process

• Any given machine, i.e., component, may consist of a combination of single machines or composite machines

Page 25: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

25

• The concrete example is given in the following UML diagram

• Note that the diagram includes a method, getMachineCount()

• As always, the devil is in the details• Once you come up with a design pattern at

the macro level, the question becomes, how do you implement the methods it contains?

Page 26: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

26

Page 27: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

27

• Note that in the diagram the superclass, MachineComponent, is shown in italics

• In UML this means that MachineComponent is an abstact class

• The method getMachineCount() is also in italics and abstract

• Naturally, the subclasses have to implement this abstract method

Page 28: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

28

• Note also that the implementation of MachineComposite is based on the Java collection class List

• The MachineComposite class has an instance variable which is a list containing references to the components that an object of the class contains

Page 29: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

29

• In general, when implementing methods in the subclasses, the implementation for a leaf will be a “one shot deal”

• It is reasonable to expect that implementation for composite class will involve iterating over the elements of the component list

• Because the two classes have a common interface, they will both implement methods with the same name

• In the implementation of the method in the composite, when iterating over the component list, the list may contain references to both leaves and composites

Page 30: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

30

• When iterating over the elements of the list, the same method name can be called on each element

• Polymorphism and dynamic binding make this possible

• If an element of the list is a leaf, calling the method will cause the leaf version of the method to be used

• If an element of the list is a composite, calling the method will cause the composite version of the method to be used

Page 31: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

31

• In this example, elements of the list will be typed MachineComponent and the method in question is getMachineCount()

• The Machine class will have a version of the method that simply returns the value 1

• The MachineComposite class will have a version of the method that iterates over its components list, calling the method on its elements, accumulating a count

• Depending on whether an element is a Machine or a MachineComposite, polymorphism and dynamic binding will determine which version of the method is called

Page 32: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

32

• Challenge 5.2• Write the code for the getMachineCount()

methods implemented by Machine and MachineComposite

Page 33: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

33

• Comment mode on:• It should be apparent that getMachineCount()

simply returns 1 for a single, simple instance of the Machine class

• As suggested by the earlier discussion, the implementation in the MachineComposite class will involve iterating over its list of components, accumulating the return values of recursive calls to getMachineCount() on them

Page 34: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

34

• Solution 5.2• For the Machine class, getMachineCount()

should be something like:• public int getMachineCount()• {• return 1;• }

Page 35: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

35

• The class diagram shows that MachineComposite uses a List object to track its components. To count the machines in a composite, you might write:

Page 36: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

36

• public int getMachineCount()• {• int count = 0;• Iterator i = components.iterator();• while(i.hasNext())• {• MachineComponent mc = (MachineComponent)

i.next();• count += mc.getMachineCount();• }• return count;• }

• If you’re using JDK 1.5 [or later], you may have used an extended for loop [a for each loop].

Page 37: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

37

• Notice that the MachineComposite implementation of getMachineCount() is both iterative and recursive at the same time

• For any given node, in essence, you iterate over its children

• On each child you make a recursive call to get its machine count

• In the case of a simple machine, there is no further recursion

• In the case of a composite, the pattern is repeated of iterating over the children getting the machine count

Page 38: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

38

• The book suggests a few more methods that might be added to the composite example based on machines

• They are given in the following table

Page 39: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

39

Page 40: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

40

• The book observes that you would expect the implementation of each of these methods in the MachineComposite class to be recursive

• This is not a surprise, considering that the implementation of getMachineCount() was recursive

• The book gives the challenge 5.3 in the form of the table on the next overhead

Page 41: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

41

Page 42: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

42

• Solution 5.3• See the next overhead

Page 43: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

43

Page 44: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

44

Composites, Trees, and Cycles

• The book seems to make this a little more complicated than necessary

• In most cases, it seems likely that the logic of a composite would require that it be a tree

• If this is the case, then it might be helpful to make sure the code included implementation of the functionality described on the next overhead

Page 45: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

45

• At the very least, including a method or methods that made it possible to check whether a created structure was a tree

• Or, include code in method implementations that disallowed adding nodes in such a way that a non-tree structure resulted

Page 46: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

46

• On the other hand, maybe the code doesn’t prevent the creation of non-tree structures and something that isn’t tree like is either desirable, or could result inadvertently

• In this case, the implementations of methods like getMachineCount() would have to include code that made sure that iteration only counted elements once, even if the structure containing them was not a tree

Page 47: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

47

• In general, the presence of some sort of cycle in the data structure would mean that it wasn’t really a tree

• The book introduces some notation and simple graph theory in order to define trees and talk about cycles

• Objects in UML are represented by rectangles, and references between them are represented by solid lines with open arrowheads

• The UML diagram on the next page shows a simple directed graph, which happens to be a path (a sequence of references from one object to another)

• This example clearly does not contain a cycle

Page 48: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

48

Page 49: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

49

• A graph is a tree if it has one node, a root node, that has no references to it

• And every other node has only one parent node, i.e., only one node that refers to it

• The term cycle refers to a sequence of references where a given node appears twice

• Any data structure that contains a cycle can’t be a tree

Page 50: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

50

• Consider the code shown on the next overhead• Assume that you can construct instances of different

kinds of simple and composite machines• Also assume that there is an add() method that

implements the navigability relationship shown by the open arrowheads in UML object diagrams

• There is no need to try and trace out what the code does

• That is immediately shown in the diagram that follows it

Page 51: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

51

• public static MachineComposite plant()• {• MachineComposite plant = new MachineComposite(100);• MachineComposite bay = new MachineComposite(101);• Machine mixer = new Mixer(102);• Machine press = new StarPress(103);• Machine assembler = new ShellAssembler(104);• bay.add(mixer);• bay.add(press);• bay.add(assembler);• plant.add(mixer);• plant.add(bay);• return plant;• }

Page 52: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

52

• The next overhead shows the UML diagram of the relationships between the objects created by the foregoing code

Page 53: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

53

Page 54: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

54

• This is probably not a desirable situation• Logically, it would seem to make sense for a

given object (the mixer) to be referred to only by its immediate parent (bay) not its ultimate parent (plant)

• However, the point is that it is possible to create this structure, and it’s necessary to be able to deal with it

Page 55: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

55

• It should be apparent that the result is not a tree• It is somewhat unfortunate that the book has

discussed “non-tree-ness” in terms of cycles in directed graphs

• As a directed graph, this diagram doesn’t show a cycle

• However, the mixer:Machine object in the diagram can be reached twice, via different, linked paths

Page 56: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

56

• In other words, mixer:Machine has two parent nodes, the List belonging to plant:MachineComposite and the List belonging to bay:MachineComposite

• For this reason the structure is not a tree, even though as a directed graph it doesn’t have a cycle

• If the graph were represented in non-directed form, then plant to bay to mixer to plant would essentially be a cycle

Page 57: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

57

• At any rate, such a structure is possible, and the task is to write correct implementations of the getMachineCount() method

• The straightforward implementation of the getMachineCount() method for a simple machine shown on the next overhead should still be correct

Page 58: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

58

• public int getMachineCount()• {• return 1;• }

Page 59: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

59

• However, if a given node object can be reached twice, by different paths, the simple, recursive getMachineCount() method for MachineComposite given earlier will no longer be correct

• The code is repeated on the next overhead for reference

• Observe that if it were run on the structure previously shown, the mixer would be counted twice, and the machine count returned by the method would be 1 greater than the correct answer

Page 60: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

60

• public int getMachineCount()• {• int count = 0;• Iterator i = components.iterator();• while(i.hasNext())• {• MachineComponent mc = (MachineComponent) i.next();

• count += mc.getMachineCount();• }• return count;• }

Page 61: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

61

• The book concretely illustrates the assertion concerning the current version of the code with a challenge

• Challenge 5.4• What does the program on the following

overhead print out?

Page 62: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

62

• package app.composite;• import com.oozinoz.machine.*;• public class ShowPlant• {• public static void main(String[] args)• {• MachineComponent c =

OoozinozFactory.plant();• System.out.println(“Number of

machines: “ + c.getMachineCount());• }• }

Page 63: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

63

• Comment mode on:• The program shown on the previous overhead

creates the non-tree structure diagrammed earlier

• It then calls the getMachineCount() method on the structure

Page 64: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

64

• Solution 5.4• The program prints out• Number of machines: 4• There are, in fact, only three machines in the

plant factory, but the mixer is counted by both plant and bay. Both of these objects contain lists of machine components that refer to the mixer

Page 65: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

65

• Solution 5.4, cont’d.• The results could be worse. If, say, an

engineer adds the plant object as a component of the bay composite, a call to getMachineCount() will enter an infinite loop

Page 66: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

66

• Comment mode on:• Notice what they’re saying here• This example was not a tree, but it also did not contain a cycle• As a result, it gave an incorrect count• If it had contained a cycle, that’s when you would enter an

infinite loop• From the point of view of the data structure created, this is a

loop through the cycle• From the point of view of the code, because the method

implementation is recursive, this structural loop would cause an infinite sequence of recursive calls

Page 67: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

67

• The book pursues the idea of dealing with non-tree structures in this way

• It states that the application that allows structures to be created should check whether a node already exists in some component before allowing it to be added to the structure

• The book also states that a simple way to do this is to maintain a set of existing nodes

Page 68: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

68

• The book introduces a method named isTree()• isTree() traverses a data structure, checking

see whether any node is encountered more than once

• If so, then isTree() returns false

Page 69: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

69

• The idea is that if you wanted to, you could include calls to isTree() in an implementation in such a way that a node could not be added if it would cause isTree() to return false

• This would protect against the creation of non-tree structures

• On the other hand, in some domains, non-tree structures might be allowed

• In that case, isTree() would still be a useful addition to a set of methods because it would tell you what kind of structure you were dealing with at any given time

Page 70: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

70

• The following UML diagram shows the Composite design pattern with an isTree() method added to it

• Notice that the suggested implementation makes use of the Java Set class

• Notice also that the MachineComponent class shows two isTree() methods, one abstract and one concrete

• How this works will be described in greater detail after the diagram

Page 71: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

71

Page 72: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

72

• As noted earlier, the component class has two isTree() methods, one abstract and one concrete

• The abstract method takes a parameter• The concrete method does not• This concrete/abstract dichotomy is not necessarily

an inherent aspect of the design pattern• However, how these methods are declared and

implemented in the classes of the pattern show a certain subtlety which is worth noting

Page 73: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

73

• Superficially, these declarations may seem confusing and potentially complex

• Understanding them requires an understanding of polymorphism and dynamic binding

• This combination of abstract and concrete methods has a beneficial effect

• It minimizes the number of different places where the same method signature has to be implemented in the set of classes

Page 74: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

74

• The basic idea underlying isTree()/isTree(s:Set) comes down to these two points:

• In order to tell whether something is a tree, you have to maintain a set of nodes and call a method that passes such a set of nodes

• However, from client code, for example, you would like to simply be able to call isTree() without having to pass a set parameter

• You would like the classes of the design pattern to take care of implementing versions which require a parameter (and are hidden from client code)

Page 75: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

75

• In the superclass, MachineComponent, there is an abstract method isTree(set:Set)—a version which takes a set parameter—which the subclasses have to implement

• In the superclass, MachineComponent, there is also a concrete method isTree()—a version which doesn’t take a parameter—which the subclasses simply inherit

Page 76: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

76

• The implementation of the concrete version of the isTree() method in MachineComponent is based on the abstract version

• The book refers to this as delegation• This is how the book describes the relationship between the

two versions of the method:• The MachineComponent code delegates an isTree() call to its

abstract isTree(s:Set) method• In other words, the isTree() implementation contains a call to

isTree(s:Set)• The declaration/implementation of the two methods in the

superclass is shown on the next overhead

Page 77: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

77

• public boolean isTree()• {• return isTree(new HashSet());• }

• protected abstract boolean isTree(Set s);

Page 78: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

78

• The question that might (or should) be on your mind is this

• There is no implementation of abstract method• What does it mean, then, to call the abstract

method in the implementation of the concrete method?

• Is this allowed? If so, how does it work?• It is allowed and it does work• The explanation of how it works follows

Page 79: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

79

• The isTree(set:Set) method is abstract—but for this reason, the class that contains it is abstract

• This means that there can be no instances of the abstract class

• As a consequence, the only real cases where the concrete method is called are when it is inherited and called on instances of the subclasses

Page 80: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

80

• At this point, it should be clear that the non-implementation of the abstract version of the method in the superclass is not a problem

• The subclasses are obligated to provide implementations of the abstract method

• When the inherited concrete method is called on a subclass object, the version of the method that takes a parameter, which is called in the body of that method, will be the one defined in the subclass

• The fact that this scheme works is the result of polymorphism and dynamic binding

Page 81: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

81

• What is accomplished by this?• It is possible to call isTree() without a

parameter on things that are typed MachineComponent, namely objects that are either Machine and MachineComposite

• In other words, the desired interface for client code is isTree() without a parameter

Page 82: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

82

• Internally, isTree(set:Set) with a parameter is needed in order to support the logic of checking whether an object is a tree

• The subclasses only need to implement isTree(set:Set)

• They can then inherit the version without a parameter

Page 83: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

83

• In theory, in an application program you could directly call the versions that take a parameter

• That would mean providing a parameter• In practice, the versions that take a parameter

would only be called as a result of an initial call to the version that doesn’t take a parameter

• This is the version inherited from the superclass, where the implementation includes the construction of the needed set parameter

Page 84: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

84

• To reach the crux of the matter, in order to complete the design as outlined so far, it’s necessary to provide subclass implementations of the abstract isTree(set:Set) method that takes a set parameter

• The implementation for the simple Machine class is straightforward

• The implementation for the MachineComposite class will be recursive, and in the recursion the sets of visited nodes will be passed down by calling the version of the isTree(set:Set) method that takes a parameter

Page 85: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

85

• The book provides this code for the simple Machine class

• protected boolean isTree(Set visited)• {• visited.add(this);• return true;• }

Page 86: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

86

• A simple machine by itself always satisfies the definition of a tree

• That accounts for the fact that the method always returns true

Page 87: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

87

• A simple machine may also be part of a composite, and the call to isTree(s:Set) on this object may be the result of a recursion in the call to isTree(s:Set) on the composite that contains it

• At that point the simple machine has to be added to the list of nodes visited

• That accounts for the first line of code in the method implementation, where “this” is added to the visited set

• Keep in mind that the parameter is a reference, so after returning from this call, the addition of the object is reflected in the set that belongs to the calling method

Page 88: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

88

• The MachineComposite implementation of isTree(set:Set) is recursive

• It has to add the object it is called on to the visited set• Just to keep things straight, remember these two things

– The isTree(s:Set) method of MachineComposite deals with a set of visited node objects

– The MachineComposite class also contains a List of all its components

• You don’t want to confuse the visited set and the component list

Page 89: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

89

• The isTree(set:Set) method for MachineComposite iterates over the composite’s components

• In that iteration, isTree(set:Set) is called on each component

• The method should (will) return false under either of these two conditions:– Either a component is encountered that is already in the

visited set– Or a recursive call to isTree(set:Set) on one of its elements

returns false• Otherwise, the method should return true

Page 90: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

90

• Challenge 5.5• Write the code for

MachineComposite.isTree(Set visited)

• Solution 5.5• A reasonable implementation of

MachineComposite.isTree() is [see next overhead]:

Page 91: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

91

• protected boolean isTree(Set visited)• {• visited.add(this);• Iterator i = components.iterator();• while(i.hasNext())• {• MachineComponent c = (MachineComponent) i.next();• if(visited.contains(c) || !c.isTree(visited))• return false;• }• return true;• }

Page 92: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

92

The End?

• The rest of the chapter is on the topic of composites with cycles

• If there is time, it will be covered in class• Otherwise, it will be up to students to read the

sections in the book and the remainder of these overheads on their own

Page 93: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

93

Composites with Cycles

• The book at this point concedes that the previous example of a structure that was not a tree could be regarded as an accident

• Letting the mixer have two parents is a mistake to be avoided in modeling the situation

• However, there are problem domains where cycles may be a correct part of the model

Page 94: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

94

• The book returns to Oozinoz for an example• This time the topic is modeling the

manufacturing process rather than modeling the factory machines

• For the sake of background, the book describes some of the manufacturing process

• It also provides the following illustration of a fireworks shell

Page 95: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

95

Page 96: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

96

• The following UML diagram shows how processes are modeled using the Composite design pattern

• At the top of the hierarchy is the ProcessComponent class

• Under it is the ProcessStep class• A ProcessStep would be a single, discrete step

in the manufacturing process

Page 97: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

97

• Under the ProcessComponent class is also the ProcessComposite class

• A component of a process may be an instance of ProcessComposite, which contains a List of constituent subprocesses

• The ProcessComposite class also has two subclasses, ProcessAlternation and ProcessSequence

Page 98: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

98

Page 99: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

99

• The UML diagram by itself doesn’t reveal what will be the critical point of this discussion

• However, the explanation of the manufacturing process in the text reveals it

• After shells are manufactured, they are inspected

• If they do not pass quality control, they have to be reworked

Page 100: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

100

• In the Oozinoz world, you don’t just toss the ingredients back in the bin, you disassemble the shell, apparently saving as much completed work as possible

• Then you make the shell again• This is the conceptual part of the Oozinoz

model that introduces a cycle which is considered normal, not an aberration

Page 101: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

101

• Figure 5.8 is an incomplete diagram showing the manufacturing process as a sequence of objects with references to each other

• The book states that the reworkOrFinish subprocess takes one of two alternative paths, either disassembly followed by make, or finish

• It is the statement “disassembly followed by make” which reveals the potential cycle in the manufacturing process

• Manufacturing starts with make, and in the case of a defective shell, starts over again with make

Page 102: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

102

Page 103: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

103

• Challenge 5.6• Figure 5.8 shows the objects in a model of the

shell assembly process. A complete object diagram would show links between any objects that refer to each other. For example, the diagram shows the references that the make object retains. Your challenge is to fill in the missing links in the diagram

Page 104: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

104

• Solution 5.6• Your solution should show the links in Figure B.4• Comment mode on:• Notice that the hard part, the cycle, was pretty much given

away by the text• The easier part was also essentially given away, but it might

not have been quite as evident• Some of the boxes have more than one arrow exiting from

them, representing alternative outcomes and paths during the manufacturing process

• The sequence of boldface arrows highlights the cycle

Page 105: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

105

Page 106: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

106

• In the earlier example the book worked with an isTree() method

• The implicit idea was that having a tree like structure was desirable

• The isTree() method would make it possible to detect when something was “wrong”

• Something wrong would cause the node count to be wrong, for example

Page 107: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

107

• Now the book wants to consider how to implement methods correctly if cycles are allowed in the structure

• Before considering the code example, it is helpful to look at the outline of the methods provided in the UML diagram given earlier

Page 108: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

108

Page 109: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

109

• The getStepCount() method in this example is somewhat analogous to the getMachineCount() method in the previous example

• However, note that instead of counting all instances of steps, getStepCount() is intended to count only the distinct leaf nodes in a path

• Since cycles may be present, any given path may be “endless”, but even so, it will only contain a finite number of distinct leaf nodes

Page 110: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

110

• The implementation of getStepCount() is similar to getMachineCount in the overall approach to implementation

• There is a version which takes a Set parameter and a version which doesn’t

• The version that doesn’t works by delegation to the version that does

Page 111: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

111

• In other words, this would be part of the implementation of the component class:

• public int getStepCount()• {• return getStepCount(new HashSet());• }• public abstract int getStepCount(Set visited);

Page 112: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

112

• The implementation of the version of the method that takes the parameter is simple for the single ProcessStep class

• It will be shown on the next overhead• Note that it adds the name of the leaf to the list, not the object

itself• Once again, the reason for this that method isn’t supposed to

count all of the objects in a path, but the distinct leaf nodes in a path

• Various process components may be repeated in a single manufacturing path

• If the repeated components have the same name, then the nodes they contain will not be counted again

Page 113: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

113

• public int getStepCount(Set visited)• {• visited.add(name);• return 1;• }

Page 114: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

114

• The version of the getStepCount(Set visited) method for the ProcessComposite class is recursive

• The getMachineCount() method for the MachineComposite class was recursive

• However, getMachineCount() method did not protect against cycles

Page 115: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

115

• The implementation of the getStepCount() method has to produce the correct result even if a cycle is present in the process composite

• First of all, this means that like the version of the method for a simple Process, this method will work with names of processes in the visited list

• It also means that the structure of the method will not be exactly the same as the structure of the getMachineCount() or isTree() methods

Page 116: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

116

• The code for the method is shown on the next overhead

• In addition to the differences noted already, the implementation is also different because it uses a for loop rather than iteration

• Presumably, this is done simply to show an alternative approach

• It does not appear that this is part of the logic of avoiding infinite looping/recursion

Page 117: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

117

• public int getStepCount(Set visited)• {• visited.add(getName());• int count = 0;• for(int i = 0; i < subprocesses.size(); i++)• {• ProcessComponent pc = (ProcessComponent)

subprocess.get(i);• if(!visited.contains(pc.getName()))• count += pc.getStepCount(visited);• }• return count;• }

Page 118: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

118

• Honestly, this code is not especially easy to understand

• As usual, figuring out what’s happening with recursion takes some close study

• I am running out of explanations to put in these overheads

Page 119: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

119

Consequences of Cycles

• If cycles are allowed in a structure, implementing methods will require making sure that you don’t “hit” the same node twice, depending on the exact purpose of the method

• Other operations will simply make no sense• For a structure with a cycle, you can count the number of

distinct leaf nodes in a path, for example• However, you can’t compute the length of a path• The path with a cycle is endless, and any method to do this

computation will loop/recur endlessly• It will also not be possible to implement any method which

relies on the existence of a single parent for every node in the structure

Page 120: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

120

Summary

• The Composite design pattern contains two concepts

• A group can contain individual items or groups of items

• The pattern makes sure that the individual items and the groups of items share a common interface

• This can be done by means of an abstract class or a Java interface

Page 121: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

121

• The Composite design pattern can easily lead to recursive method implementations

• If that is the case, then you can take steps to make sure that structures are always trees

• You can also take steps to make sure that method implementations will still work if non-tree structures are allowed

Page 122: Design Patterns in Java Chapter 5 Composite Summary prepared by Kirk Scott 1.

122

The End