design patterns in java chapter 10 mediator

88
Design Patterns in Java Chapter 10 Mediator Summary prepared by Kirk Scott 1

Upload: renate

Post on 23-Feb-2016

79 views

Category:

Documents


1 download

DESCRIPTION

Design Patterns in Java Chapter 10 Mediator. Summary prepared by Kirk Scott. The Mediator design pattern is one that can’t be captured in a single, neat UML diagram It is based on a general idea that can be expressed in words and could have many different implementations in practice - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: Design Patterns in Java Chapter 10 Mediator

1

Design Patterns in JavaChapter 10Mediator

Summary prepared by Kirk Scott

Page 2: Design Patterns in Java Chapter 10 Mediator

2

• The Mediator design pattern is one that can’t be captured in a single, neat UML diagram

• It is based on a general idea that can be expressed in words and could have many different implementations in practice

• The background can be expressed in terms of responsibility again

Page 3: Design Patterns in Java Chapter 10 Mediator

3

• The general rule is that objects are responsible for themselves

• In other words, classes should contain some well-defined, limited, and coherent data set, along with the methods needed to work with the data

• Classes, in general, should not be heavily reliant on objects of other classes to implement needed functionality

Page 4: Design Patterns in Java Chapter 10 Mediator

4

• On the other hand, there are design patterns that go in the other direction

• One of the explanations for the existence of the Singleton pattern was that it concentrated responsibility in one class

• There could be only one instance of that class• Therefore, by definition, all other classes that

needed to work with the singleton class had to work with the singleton instance

Page 5: Design Patterns in Java Chapter 10 Mediator

5

• The mediator pattern is another pattern that in a sense concentrates responsibility

• Consider this scenario: In a group of objects, each one “is aware of” or has a reference to every other member of the group

• The set of relationships itself becomes an abstraction that might be implemented as a separate class

Page 6: Design Patterns in Java Chapter 10 Mediator

6

• On the one hand, introducing a new class for the relationships is a form of “factoring out”

• On the other hand, the new class concentrates responsibility for the relationships among objects and reduces their responsibility for themselves

• The individual objects then become dependent on the class that maintains the relationships

• In the code, the individual objects relate only to the class in the middle, not with each other

Page 7: Design Patterns in Java Chapter 10 Mediator

7

• This new class in the middle is a mediator class• Book definition: The intent of the Mediator

pattern is to define an object that encapsulates how a set of objects interact; this promotes loose coupling, keeping the objects from referring to one another explicitly, and lets you vary their interactions independently.

Page 8: Design Patterns in Java Chapter 10 Mediator

8

• Note the recurrence of the term “coupling” in this definition

• Here, the desire is loose coupling• In another design pattern the goal was stated as

decoupling• Decoupling among the base classes results from the

use of the Mediator design pattern • The design pattern concentrates responsibility in the

mediator and the base classes have to be coupled with it

Page 9: Design Patterns in Java Chapter 10 Mediator

9

• In some reality that is being modeled, individual objects really are linked with each other

• However, by using the mediator design pattern, from a code writing point of view the individual objects are made less directly dependent on each other to maintain the relationship

• The relationships themselves truly are a separate concept, and correctly implementing them in a separate class abstracts out the responsibility for maintaining relationships

Page 10: Design Patterns in Java Chapter 10 Mediator

10

• The book pursues two examples to illustrate the use of the Mediator design pattern

• 1. The pattern can become apparent/be used when developing GUI’s with multiple parts in increasingly complex relationships

• 2. The pattern can also become apparent when modeling the real world where objects have relationships with each other and the code needs to reflect those relationships

Page 11: Design Patterns in Java Chapter 10 Mediator

11

A Classic Example: GUI Mediators

• Unfortunately, because there is no one UML diagram that encapsulates the mediator idea, it can be a little hard to grasp

• The book shows a GUI, shows some code, and shows a refactoring

• At the end, it basically comes down to, “Voila—and now you see how these things don’t interact directly with each other—they interact through this other class in the design.”

Page 12: Design Patterns in Java Chapter 10 Mediator

12

• The first example consists of a graphical application that has the interface shown on the following overhead

• The underlying scenario is that the factory has machines in it, and the machines at any given time have a set of tubs of materials that belong to them

Page 13: Design Patterns in Java Chapter 10 Mediator

13

Page 14: Design Patterns in Java Chapter 10 Mediator

14

• The idea is that if you select a machine from the first column, the tubs belonging to it appear in the second column

• Then you pick a tub in the second column and a machine in the third column

• Once three things are highlighted, you can press the “Do it!” button in order to make the move

• Of the course, the move is not the physical move, but a changing of the relationships among tubs and machines as represented in the software model

Page 15: Design Patterns in Java Chapter 10 Mediator

15

• The authors paint out the scenario further in this way

• An interface like this can be developed using a wizard

• However, the wizard produces cookie-cutter code that doesn’t necessarily fit a nice design pattern

Page 16: Design Patterns in Java Chapter 10 Mediator

16

• The wizard produced a class named MoveATub, that is basically a monolithic application

• The UML for this class is given on the next overhead• The desire is to refactor this design so that is better• In other words, the desire is to break it into parts

where the responsibilities are clearly divided• In the long run this will make the code easier to

maintain and modify

Page 17: Design Patterns in Java Chapter 10 Mediator

17

Page 18: Design Patterns in Java Chapter 10 Mediator

18

• The book observes that the methods in the MoveATub class are a mixture

• A large number of them are constructor methods like the ones that have been seen in previous examples

• For example, there is a method assignButton(), which is the method which constructs the “Do it!” button

• Its code is given on the next overhead for reference• The authors are in love with lazy initialization…I find

it kind of pointless and irritating…

Page 19: Design Patterns in Java Chapter 10 Mediator

19

• private JButton assignButton()• {• if(assignButton == null)• {• assignButton = new JButton(“Do it!”);• assignButton.setEnabled(false);• assignButton.addActionListener(this);• }• return assignButton;• }

Page 20: Design Patterns in Java Chapter 10 Mediator

20

• Aside from the fact that a bunch of the methods can be classified as constructors, you may note the following

• Because the MoveATub class is monolithic, it’s constructing objects of various different kinds, like the button, lists of machines and tubs, and so on

• In other words, the elements of the problem domain are mixed with GUI elements

Page 21: Design Patterns in Java Chapter 10 Mediator

21

• Looking at the methods you also find things like valueChanged() and updateTubList() which suggest actions and listeners

• The authors give the code for the valueChanged() method for reference

• It is shown on the following overhead

Page 22: Design Patterns in Java Chapter 10 Mediator

22

• public void valueChanged(ListSelectionEvent e)• {• // …• assignButton().setEnabled(• !tubList().isSelectionEmpty()• && !machineList().isSelectionEmpty());• }

Page 23: Design Patterns in Java Chapter 10 Mediator

23

• The book observes that at the very least you might consider moving the event handling methods into a different class and that would be a step towards applying the mediator pattern

• As a matter of fact, if you go back to the Observer pattern, it becomes clear that the use of listeners is already a type of mediation

Page 24: Design Patterns in Java Chapter 10 Mediator

24

• When using the observer concept, one object doesn’t notify or update another directly

• Instead, a listener or observer or whatever stands between the related objects

• By definition, the thing in the middle is a mediator

• The moral of this story is that the design patterns are not mutually exclusive

Page 25: Design Patterns in Java Chapter 10 Mediator

25

• Challenge 10.1• Complete the diagram in Figure 10.3 to show a

refactoring of MoveATub, introducing a separate mock database class and a mediator class to receive the events of the MoveATub GUI.

Page 26: Design Patterns in Java Chapter 10 Mediator

26

• Comment mode on:• As usual, doing this on your own verges on the impossible• What, for example, does the book mean by a mock

database?• It wouldn’t be a difficult question if all you had to do was

divide up the named methods given in the previous UML diagram, but when you see the book’s answer, other methods have been introduced

• As usual, the only practical approach is to just look at the book’s solution and try and figure out what it means

Page 27: Design Patterns in Java Chapter 10 Mediator

27

Page 28: Design Patterns in Java Chapter 10 Mediator

28

• Solution 10.1• Figure B.11 shows a solution.

Page 29: Design Patterns in Java Chapter 10 Mediator

29

Page 30: Design Patterns in Java Chapter 10 Mediator

30

• What is to be gleaned from the UML diagram of the solution?

• MoveATub2 now is pretty much limited to the graphical components of the application

• NameBase is the so-called mock database• This is the part of the application that is

problem domain, or state oriented• It keeps track of machines and their tubs

Page 31: Design Patterns in Java Chapter 10 Mediator

31

• MoveATubMediator implements the ActionListener and ListSelectionListener interfaces

• It contains the actionPerformed(), valueChanged(), and updateTubList() methods

• As its name indicates, this is the (GUI) mediator• When things happen in the GUI, actions are taken

indirectly on the NameBase, through the mediator

Page 32: Design Patterns in Java Chapter 10 Mediator

32

• It is also possible for the mediator to take actions on the GUI, like enabling or disabling a button

• As stated already, this should seem familiar• The whole observer structure is essentially a

kind of mediation• The most common example of mediation is

this use in GUI development

Page 33: Design Patterns in Java Chapter 10 Mediator

33

• Challenge 10.2• Draw a diagram that shows what happens

when the user clicks the Do it! Button. Show whichever objects you think are most important, and show the messages that pass between these objects.

Page 34: Design Patterns in Java Chapter 10 Mediator

34

• Solution 10.2• Figure B.12 shows one solution.

Page 35: Design Patterns in Java Chapter 10 Mediator

35

Page 36: Design Patterns in Java Chapter 10 Mediator

36

Mediators of Relational Integrity

• The most common use of the mediator pattern may be in GUI’s, but there are others

• In general, in any case where there are numerous or complicated relationships between objects, it may be desirable to abstract the relationships out

• This reduces the coupling between objects

Page 37: Design Patterns in Java Chapter 10 Mediator

37

• It also has this signal advantage, as noted earlier• The relationships really do have an existence in a

design and may be no less important than the objects

• By abstracting the relationships out, the rules for them can be standardized and you assure yourself that all objects that participate in relationships rely on the same implementation logic

Page 38: Design Patterns in Java Chapter 10 Mediator

38

• The book is going to pursue the idea of relationships using the machines and tubs of Oozinoz

• There is an interesting contrast between the first and second examples

• In the first example, the Mediator design pattern was illustrated by the graphical user interface part of an application that worked with machines and tubs

Page 39: Design Patterns in Java Chapter 10 Mediator

39

• The machines and tubs, or lists of machines and tubs, were simply relegated to that part of the design having to do with the business model

• Now it is the relationships between the machines and tubs that are of interest and which will be used to illustrate mediation

• Consider the table shown on the next overhead

Page 40: Design Patterns in Java Chapter 10 Mediator

40

Page 41: Design Patterns in Java Chapter 10 Mediator

41

• The table shows a one-to-many relationship between machines and tubs

• In physical reality a tub can only belong to one machine at a given time

• Also, in this scenario, one machine can have zero or more tubs at a time

• As long as the tub entries in the table are unique, the table represents this reality

• Multiple entries for the same machine in the second column simply allow a given machine to have more than one tub at a time

Page 42: Design Patterns in Java Chapter 10 Mediator

42

• The book has a grey section on the topic of relational integrity

• The topic is not nearly as difficult or theoretical as they seem to be trying to make it

• I see no reason to work my way through it in the overheads

Page 43: Design Patterns in Java Chapter 10 Mediator

43

• The topic of interest is simply how the table would translate into relationships between objects in a Java implementation

• On the following overhead a UML diagram is given which shows one-to-many relationships between machines and tubs

• The requirement of one-to-many in the table was easily expressed by stating that the tub entries had to be unique while the machine entries did not have to be

Page 44: Design Patterns in Java Chapter 10 Mediator

44

Page 45: Design Patterns in Java Chapter 10 Mediator

45

• The critical observations about object-oriented code are these

• Even though the diagram shows only one-to-many relationships, there is nothing in the UML notation of boxes and arrows that mandates this

• Similarly, there is no automatic support in programming languages like Java for concepts like this

Page 46: Design Patterns in Java Chapter 10 Mediator

46

• That means that the application developer has to enforce this

• The idea behind a mediator is this:• Do you want to try and do this “every time”—that is

write code in the classes of the participating objects so that correct relationships are maintained?

• Or would you prefer to write a general solution where the rules are enforced by code in a single, separate class?

Page 47: Design Patterns in Java Chapter 10 Mediator

47

• Notice that in the UML diagram, the arrows are double-headed

• This means that machines know which tubs are theirs and tubs know which machine they belong to

• In other words, there are references in the code for the objects going both ways

Page 48: Design Patterns in Java Chapter 10 Mediator

48

• The book illustrates the pitfalls of trying to maintain relationships with an example

• Suppose a developer wrote these lines of code to change which machine a tub belonged to

• // Tell tub about machine, and machine about tub

• t.setMachine(m);• m.addTub(t);

Page 49: Design Patterns in Java Chapter 10 Mediator

49

• Challenge 10.3• Assume that the objects begin as shown in Figure

10.4. Suppose that the object t represents tub T308 and that the object m represents the machine Fuser-2101. Complete the object diagram in Figure 10.5, showing the effects of the code that updates the tub’s location. What defect does this reveal?

• [Figures 10.4 and 10.5 are shown on the next overheads.]

Page 50: Design Patterns in Java Chapter 10 Mediator

50

Page 51: Design Patterns in Java Chapter 10 Mediator

51

Page 52: Design Patterns in Java Chapter 10 Mediator

52

• Solution 10.3• Figure B.13 shows an updated object diagram.

Page 53: Design Patterns in Java Chapter 10 Mediator

53

Page 54: Design Patterns in Java Chapter 10 Mediator

54

• Solution 10.3, cont’d.• The problem that the developer’s code introduces is

that StarPress2402 still thinks that it has tub T308. In a relational table, changing the machine attribute of a row automatically removes the tub from the prior machine. This automated removal does not occur when the relation is dispersed across a distributed object model. The proper modeling of the tub/machine relation requires special logic that you can remove to a separate mediator object.

Page 55: Design Patterns in Java Chapter 10 Mediator

55

• The book suggests that the simplest way to maintain relational integrity like this is to actually rely on a table

• The table concept can be coded in a separate class, a mediator

• Then the objects won’t refer to each other directly

Page 56: Design Patterns in Java Chapter 10 Mediator

56

• They will have their relationships captured in the table

• The establishment of relationships will be done through the mediator class’s interface

• The book illustrates the idea in the following UML diagram

Page 57: Design Patterns in Java Chapter 10 Mediator

57

Page 58: Design Patterns in Java Chapter 10 Mediator

58

• As usual, the book has thought things out in advance and the diagram includes some method names

• Also, as usual, there is no guarantee that the methods shown in the UML diagram are a complete set of the methods needed

• The next task is to consider what the relationships between the classes mean, what the methods mean, and how they would be implemented

• Before looking at code, consider these points arising from the UML diagram

Page 59: Design Patterns in Java Chapter 10 Mediator

59

• Tubs and machines have a reference to the (one) mediator• The tub and machine method names seem self-

explanatory• The point is that the tub and machine methods for adding

a tub to a machine, assigning a machine to a tub, etc., would be implemented by wrapping calls to the mediator class’s methods

• The TubMediator class has an instance variable of Java type Map

• The Map implements the logic of the relational table

Page 60: Design Patterns in Java Chapter 10 Mediator

60

• The book next starts presenting code, partial code, and code based challenges

• It starts with the Tub class• A tub has an id and a reference to a (the) mediator• It has set and get methods for location, where

location refers to the machine it’s associated with• These methods wrap calls to the mediator object

Page 61: Design Patterns in Java Chapter 10 Mediator

61

• public class Tub• {• private String id;• private TubMediator mediator = null;• public Tub(String id, Tubmediator mediator)• {• this.id = id;• this.mediator = mediator;• }

Page 62: Design Patterns in Java Chapter 10 Mediator

62

• public Machine getLocation()• {• return mediator.getMachine(this);• }• public void setLocation(Machine value)• {• mediator.set(this, value);• }• public String toString()• {• return id;• }

Page 63: Design Patterns in Java Chapter 10 Mediator

63

• public int hashCode• {• // …• }• public boolean equals(Object obj)• {• // …• }

Page 64: Design Patterns in Java Chapter 10 Mediator

64

• The book provides the code for the hashCode() and equals() methods next

• The reason for needing these methods begins with the observation that the methods setLocation() and getLocation() wrap calls of this kind:

• mediator.set(this, value);• mediator.getMachine(this);• The set() and getMachine() methods wrap calls to the

Hashtable class get() and put() methods• In order for a tub to be used as a key value in a hash table,

the Tub class has to implement hashCode() and equals()

Page 65: Design Patterns in Java Chapter 10 Mediator

65

• public int hashCode()• {• return id.hashCode();• }• public boolean equals(Object obj)• {• if(obj == this) return true;• if(obj.getClass() != Tub.class)• return false;• Tub that = (Tub) obj;• return id.equals(that.id);• }

Page 66: Design Patterns in Java Chapter 10 Mediator

66

• The TubMediator class will be considered next• The Map instance variable in that class is an

instance of the Java class HashMap• On the following overhead is a snippet from

the Java API documentation for the HashMap

Page 67: Design Patterns in Java Chapter 10 Mediator

67

• Hash table based implementation of the Map interface.

• This implementation provides all of the optional map operations, and permits null values and the null key.

• (The HashMap class is roughly equivalent to Hashtable, except that it is unsynchronized and permits nulls.)

Page 68: Design Patterns in Java Chapter 10 Mediator

68

• Here is a snippet from the Java API documentation for Hashtable

• This class implements a hashtable, which maps keys to values.

• Any non-null object can be used as a key or as a value.

• To successfully store and retrieve objects from a hashtable, the objects used as keys must implement the hashCode method and the equals method.

Page 69: Design Patterns in Java Chapter 10 Mediator

69

• The way to envision the use of the hash table with tubs and machines is this:

• The hash table is like a two column table• The left column consists of look-up values,

known as keys• The right column consists of values, namely

those values that match with the keys

Page 70: Design Patterns in Java Chapter 10 Mediator

70

• In the tub/machine scenario, a tub exists in the table once

• The hash code of a tub serves as its unique identifier

• This is the hash table key• Then the identifier for the machine that the tub is

assigned to serves as the value in the hash table• Code for the TubMediator class follows

Page 71: Design Patterns in Java Chapter 10 Mediator

71

• public class TubMediator• {• protected Map tubToMachine = new HashMap();• public Set getTubs(Machine m)• {• Set set = new HashSet();• Iterator i = tubToMachine.entrySet().iterator();• while(i.hasNext())• {• Map.Entry e = (May.Entry) i.next();• if(e.getValue().equals(m))• set.add(e.getKey());• }• return set;• }

Page 72: Design Patterns in Java Chapter 10 Mediator

72

• public void getMachine(Tub t)• {• // Challenge!• }• public void set(Tub t, Machine m)• {• // Challenge!• }

Page 73: Design Patterns in Java Chapter 10 Mediator

73

• Challenge 10.4• Write the code for the TubMediator methods

getMachine() and set().

Page 74: Design Patterns in Java Chapter 10 Mediator

74

• Solution 10.4• The complete code for the TubMediator class

should look something like:• [Preliminary, explanatory material is given.

The book’s solution follows that material.]

Page 75: Design Patterns in Java Chapter 10 Mediator

75

• Comment mode on:• The book repeats the getTubs() method• I just show the missing methods• Note that their implementations are incredibly

simple• They rely entirely on the get() and put() methods

of the Hashtable class• The API documentation for these methods is

shown before the solution code is shown

Page 77: Design Patterns in Java Chapter 10 Mediator

77

• put• public V put(K key, V value)• Maps the specified key to the specified value in this hashtable.

Neither the key nor the value can be null. The value can be retrieved by calling the get method with a key that is equal to the original key.

• Specified by: put in interface Map<K,V>• Specified by: put in class Dictionary<K,V>• Parameters: key - the hashtable key.value - the value.• Returns: the previous value of the specified key in this hashtable, or

null if it did not have one.• Throws: NullPointerException - if the key or value is null.• See Also: Object.equals(Object), get(Object)

Page 78: Design Patterns in Java Chapter 10 Mediator

78

• public Machine getMachine(Tub t)• {• return (Machine) tubToMachine.get(t);• }• public void set(Tub t, Machine m)• {• tubToMachine.put(t, m);• }

Page 79: Design Patterns in Java Chapter 10 Mediator

79

• Recall that it was necessary earlier to provide implementations of hashCode() and equals() for the Tub class

• The equals() method was openly called in the getTubs() method, but neither of the methods is openly called in getMachine() or set()

• If you delved in the API you would discover that in order for instances of a class to serve as keys in a hash table, the class has to implement the hashCode() and equals() methods

Page 80: Design Patterns in Java Chapter 10 Mediator

80

• In other words, internal to the hash table get() and put() methods, there must be calls to hashCode() and equals() on the parameters

• The only lingering question is why the authors chose to implement hashCode() and equals() on the basis of a tub’s id rather that on the basis of the tub object itself

• As far as I can see in the text, the authors don’t explain this decision

Page 81: Design Patterns in Java Chapter 10 Mediator

81

• I can see no syntactical reason for not basing hashCode() and equals() on the Tub object rather than its id

• The one concrete consequence of the decision that I can see is that it will ultimately force the user to make sure that tub id’s are unique

• If you tried to put() more than one tub with the same id hashcode into the same hash table, an inconsistency would result

Page 82: Design Patterns in Java Chapter 10 Mediator

82

Back to the General Discussion

• The book returns to the general theme of whether or not it’s a good idea to include a mediator in a design

• You could code the logic for machines and tubs into those classes themselves

• The thing to remember is that such code is error prone

• You could also argue that the details of relationships are not intrinsically part of the logic of the classes themselves

Page 83: Design Patterns in Java Chapter 10 Mediator

83

• I think you could argue equally strongly that in a sense, the relationships possible between classes truly are intrinsic parts of the definitions of the classes

• However, regardless of your philosophical position, there is clearly a convenience in unifying the logic for relationships in one place

• The relationships are an abstraction of their own, and the logic for maintaining them can be centralized

• Not incidentally, in this way it becomes possible to use things like Java hash tables to enforce requirements like relational integrity

Page 84: Design Patterns in Java Chapter 10 Mediator

84

• Challenge 10.5• With respect to moving logic out of one class

and into a new one, Mediator is similar to other patterns. List two other patterns that may involve refactoring an aspect of behavior out of an existing class or hierarchy.

Page 85: Design Patterns in Java Chapter 10 Mediator

85

• Solution 10.5• The Façade pattern may help to refactor a

large application• The Bridge pattern moves abstract operations

to an interface• The Observer pattern may appear as you

refactor code to support an MVC architecture

Page 86: Design Patterns in Java Chapter 10 Mediator

86

• Solution 10.5, continued• The book now lists other patterns which haven’t been

covered yet• This is kind of pointless, but for the sake of completeness

I include them here without the book’s commentary• Flyweight, Builder, Factory Method, State, and Strategy• The moral of the story simply is that lots of design and

refactoring depend on abstracting something out and implementing it elsewhere

Page 87: Design Patterns in Java Chapter 10 Mediator

87

Summary

• The Mediator pattern supports loose coupling• Related objects don’t refer to each other directly• The Mediator pattern shows up in GUI development

where communication among components by means of an observer/observable structure (listeners)

• Whenever it may be desirable to implement the interactions between objects in a separate class, the Mediator pattern applies

• The tub/machine example illustrated this generic (non-GUI) application of the pattern

Page 88: Design Patterns in Java Chapter 10 Mediator

88

The End