900 likes | 1.11k Views
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
E N D
Design Patterns in JavaChapter 10Mediator 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 • The background can be expressed in terms of responsibility again
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
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
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
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
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.
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
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
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
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.”
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
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
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
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
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…
private JButtonassignButton() • { • if(assignButton == null) • { • assignButton = new JButton(“Do it!”); • assignButton.setEnabled(false); • assignButton.addActionListener(this); • } • return assignButton; • }
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
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
public void valueChanged(ListSelectionEvent e) • { • // … • assignButton().setEnabled( • !tubList().isSelectionEmpty() • && !machineList().isSelectionEmpty()); • }
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
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
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.
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
Solution 10.1 • Figure B.11 shows a solution.
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
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
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
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.
Solution 10.2 • Figure B.12 shows one solution.
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
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
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
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
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
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
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
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
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?
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
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);
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.]