design patterns in java chapter 3 adapter

108
Design Patterns in Java Chapter 3 Adapter Summary prepared by Kirk Scott 1

Upload: quinto

Post on 22-Feb-2016

49 views

Category:

Documents


0 download

DESCRIPTION

Design Patterns in Java Chapter 3 Adapter. Summary prepared by Kirk Scott. Adapter, Terminology and Statement of Pattern Intent. One code base is a client if it needs to make use of the functionality of methods in another code base, which would be the service provider - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: Design Patterns in Java Chapter 3 Adapter

1

Design Patterns in JavaChapter 3Adapter

Summary prepared by Kirk Scott

Page 2: Design Patterns in Java Chapter 3 Adapter

2

Adapter, Terminology and Statement of Pattern Intent

• One code base is a client if it needs to make use of the functionality of methods in another code base, which would be the service provider

• Observe the possible sequence of events in large scale or disjointed development:

• The client code is written before the service code, and the client makes calls to methods that do not end up in the service code base specifications and implementation

Page 3: Design Patterns in Java Chapter 3 Adapter

3

Adapter, Terminology and Statement of Pattern Intent, cont’d.

• Client and service code may also simply be written independently, without (advance) knowledge of each other’s interfaces

• Or, the specifications for the code bases belong to different organizations and the differences between their interfaces are simply set in stone or fixed for other reasons

• Whatever the reason, the scenario is that the service code contains useful functionality, and the underlying problem is that the client code was written to call methods by names that don’t exist in the service code

Page 4: Design Patterns in Java Chapter 3 Adapter

4

• This may sound like a screw-up and the the ideal solution might seem to be rewriting one or the other of the code bases so that the method names agree

• However, if the specifications of the service code base have been set, recoding isn’t an option

• Alternatively, once the code exists, recoding everything so that it agrees may be undesirable because it is too much work

Page 5: Design Patterns in Java Chapter 3 Adapter

5

• In a situation like this, the Adapter pattern can be used

• The basic idea is that by insightful use of interfaces and subclasses, adding one class to the system makes it possible for the client code base to use the service code base

Page 6: Design Patterns in Java Chapter 3 Adapter

6

• There are actually several adapter scenarios• The simplest case is when the client code

developer planned in advance for adaptation by implementing a Java interface of the necessary methods

• There are other scenarios which fulfill the intent of adaptation but are somewhat different due to the absence of a Java interface or for other reasons

Page 7: Design Patterns in Java Chapter 3 Adapter

7

Adapter, Terminology and Statement of Pattern Intent

• Statement of Intent:• The intent of Adapter is to provide the

interface that a client expects while using the services of a class with a different interface

Page 8: Design Patterns in Java Chapter 3 Adapter

8

Adapting to an Interface

• In the ideal case, the client developer realizes that services may eventually be required from another code base

• The client developer then creates a Java interface which includes all of the methods which the client code calls

Page 9: Design Patterns in Java Chapter 3 Adapter

9

• An Adapter class implements this interface• The Adapter class also extends the class in the

service code base which contains the useful methods

• The implementation of the interface methods in the Adapter class are based on calls to the useful, but “misnamed” methods inherited from the superclass in the service code base

Page 10: Design Patterns in Java Chapter 3 Adapter

10

• The following diagram illustrates this basic version of the Adapter design pattern

Page 11: Design Patterns in Java Chapter 3 Adapter

11

Page 12: Design Patterns in Java Chapter 3 Adapter

12

• Concretely, the client makes use of an interface, RequiredInterface, which specifies the use of a method named requiredMethod()

• The service code base contains an ExistingClass with a method named usefulMethod() which contains the needed functionality

• The NewClass is an adapter which implements the interface and extends ExistingClass

• In NewClass, the implementation of requiredMethod() is based on calls to usefulMethod()

Page 13: Design Patterns in Java Chapter 3 Adapter

13

• Before moving on, there is another aspect of this to consider

• Apparently the book considers it obvious, but when reading the book, the question arose in my mind

• In the diagram, the client is shown as making use of the interface by means of a line with an open arrowhead

Page 14: Design Patterns in Java Chapter 3 Adapter

14

• What does it mean for the client to make use of the interface?

• Typically, you might think that the client code would contain calls of this sort: newClassObject.requiredMethod()

• But this can’t be the case• The scenario is that the client doesn’t know about the

contents of the service code base, and by definition, it would have been written before the adapter class was written

Page 15: Design Patterns in Java Chapter 3 Adapter

15

• How does the client “know” to use an object that conforms to the interface, or how does it acquire an object of a class that implements the interface?

• Clearly, the client code cannot be rewritten to use objects of class NewClass

• There are two parts to the answer to this question

Page 16: Design Patterns in Java Chapter 3 Adapter

16

• The first part of the answer is that although not explicitly shown, part of the use of the client consists of passing in references to objects

• A reference to an object of NewClass could be passed into a method of the client code base

• How can this be, if the client code does not “know about” NewClass?

• Read on

Page 17: Design Patterns in Java Chapter 3 Adapter

17

• A second part of the answer is that the input parameter to a method of the client could be typed to the interface, not to a particular class

• This is an approach that didn’t come up in CS 202, but it will recur in this book

• Part of the power of interfaces is that they can be used as types

Page 18: Design Patterns in Java Chapter 3 Adapter

18

• If the client developer figured out the interface, then the client code can have objects and parameters typed to that interface wherever needed

• Then truly, all that’s required for successful adaption is the creation of an adapter class that implements the interface

• Wherever that interface is needed, references to the adapter class can be used

Page 19: Design Patterns in Java Chapter 3 Adapter

19

A More Concrete Example• The book next explains more by working with specific

example code• Oozinoz makes rockets, and in its code base is a class named

EventSim, which runs simulations of rocket performance• The code base also includes the specifications for an

interface, RocketSim, which represents rockets/rocket characteristics

• EventSim was written to make use of the RocketSim interface

• This is shown in the following UML diagram

Page 20: Design Patterns in Java Chapter 3 Adapter

20

Page 21: Design Patterns in Java Chapter 3 Adapter

21

• The foregoing description and diagram represent the client side of an illustration of the Adapter class

• In addition, Oozinoz has a PhysicalRocket class which represents rockets

• The PhysicalRocket class has a set of methods which are useful, and more or less analogous to the methods in the RocketSim interface

• Unfortunately, they do not have the same names

Page 22: Design Patterns in Java Chapter 3 Adapter

22

• Suppose you would like to run EventSim and apply it to instances of the PhysicalRocket class

• You can’t, but the situation is ripe for solution using the Adapter design pattern

• The following UML diagram illustrates creating a new class, OozinozRocket, which implements the RocketSim interface and extends the PhysicalRocket class

Page 23: Design Patterns in Java Chapter 3 Adapter

23

Page 24: Design Patterns in Java Chapter 3 Adapter

24

• Notice that the methods on the client and server sides don’t agree exactly in name or other characteristics

• Frequently there isn’t a simple one-to-one correspondence between methods with exactly the same function but different names

• In this respect, the example is relatively realistic• Things are rarely rock bottom simple and the

adapter will have to deal with the mismatch

Page 25: Design Patterns in Java Chapter 3 Adapter

25

• A brief overview reveals:• There are getMass() and getThrust() methods

in both the interface and the class• However, these methods take a time

parameter in the class methods and take no parameter in the interface

Page 26: Design Patterns in Java Chapter 3 Adapter

26

• There is also a setSimTime() method in the interface• It takes a time parameter• Recall that when implementing an interface, it is up

to the programmer to supply any needed variables• They are not specified in the interface• This suggests that some sort of time variable will be

lurking somewhere in the interface implementation

Page 27: Design Patterns in Java Chapter 3 Adapter

27

• There is also a getBurnTime() method in the server side class

• It is not immediately apparent how this might be used to implement the interface methods in the Adapter class

• On the other hand, it does seem like a potential source for the value of the time parameter

Page 28: Design Patterns in Java Chapter 3 Adapter

28

• Overall, domain knowledge (an explanation by the authors of how the simulation works) is needed in order to sort out the implementation of the Adapter class

• The authors add that RocketSim keeps an internal clock (typical of event simulators) and occasionally updates simulated objects by calling the setSimTime() method

Page 29: Design Patterns in Java Chapter 3 Adapter

29

• When implementing the OozinozRocket Adapter class, it will be necessary to maintain a time instance variable which can be passed as a parameter to the PhysicalRocket class methods as needed

• Although this really hardly seems like enough background information, the author now presents challenge 3.1

• As usual, lack of information is no problem—we’re just going to look immediately at the provided solution anyway and try to figure it out

Page 30: Design Patterns in Java Chapter 3 Adapter

30

• Challenge 3.1• Complete the class diagram in Figure 3.3 to show the

design of an OozinozRocket class that lets a PhysicalRocket object participate in a simulation as a RocketSim object. Assume that you can’t alter either RocketSim or Physical Rocket.

• Note that although in a sense the warning “Thou shalt not alter” should go without saying, it is a useful reminder of the reality that the Adapter pattern is intended to address.

Page 31: Design Patterns in Java Chapter 3 Adapter

31

Solution 3.1

Page 32: Design Patterns in Java Chapter 3 Adapter

32

• There are no surprises in the diagram shown• We were warned that a time variable would be

needed• Also, all methods of the interface are shown in the

Adapter class—as they should be• The only potentially unexpected thing is the inclusion

of a constructor specification in the Adapter class• However, this also doesn’t contain surprises• It exactly parallels the constructor in the superclass

Page 33: Design Patterns in Java Chapter 3 Adapter

33

• The devil, then, is in the code writing• In other words, you know what methods you

need to include; how do you write them?• Once again, domain knowledge will probably

be necessary• In the simplest of all possible cases, it might

be possible to wrap a call to a class method inside the body of an interface method

Page 34: Design Patterns in Java Chapter 3 Adapter

34

• On the other hand, it may also be necessary to write more complex implementations of the interface methods in order to make successful use of the functionality in the class methods

• The authors next give partial code for the Adapter class, leaving the implementations of two of the methods as challenges

Page 35: Design Patterns in Java Chapter 3 Adapter

35

• package com.oozinoz.firework;• import com.oozinoz.simulation.*;• public class OozinozRocket• extends PhysicalRocket• implements RocketSim• {• private double time;

Page 36: Design Patterns in Java Chapter 3 Adapter

36

• public OozinozRocket• (double burnArea, double burnRate,• double fuelMass, double totalMass)• {• super(burnArea, burnRate,• fuelMass, totalMass);• }

Page 37: Design Patterns in Java Chapter 3 Adapter

37

• public double getMass()• {• // Challenge!• }• public double getThrust()• {• // Challenge!• }• public void setSimTime(double time)• {• this.time = time;• }• Note the use of this.time = time• This is an evil aberration from all that’s right and good and true…

Page 38: Design Patterns in Java Chapter 3 Adapter

38

• Challenge 3.2• Complete the code for the OozinozRocket

class, including methods getMass() and getThrust().

Page 39: Design Patterns in Java Chapter 3 Adapter

39

• Before looking at the solution, consider these two observations

• 1. Obviously you don’t have to implement getBurnTime()

• It’s a method in the class, not the interface, and it’s inherited

• It also turns out that it plays no role in the implementation of the interface methods

Page 40: Design Patterns in Java Chapter 3 Adapter

40

• 2. The solution turns out to be deceptively simple

• Although the worst-case scenario is that the client developer has no advance knowledge, it seems that in this case the client developer knew or foresaw something about the service code base

• The interface includes the setSimTime() method

Page 41: Design Patterns in Java Chapter 3 Adapter

41

• Formally, there is no indication in the specifications of the getMass() and getThrust() methods of the interface that a simulation time would be needed in order to implement those methods

• However, if you look at the PhysicalRocket class and see that the analogous methods require a time parameter, then it becomes necessary to support a time variable in the interface and provide a method for setting its value

Page 42: Design Patterns in Java Chapter 3 Adapter

42

Solution 3.2

• public double getMass()• {• return getMass(time);• }• public double getThrust()• {• return getThrust(time);• }

Page 43: Design Patterns in Java Chapter 3 Adapter

43

• Just to state the obvious, both getMass() and getThrust() are overloaded in the Adapter class

• The class inherits the versions which take parameters and implements the versions which don’t

• The example ultimately turns out to be an example of the simplest kind, once you understand the treatment of the time variable

Page 44: Design Patterns in Java Chapter 3 Adapter

44

• The interface versions of the methods don’t have a time parameter

• The server code versions of the methods do have a time parameter

• In the adapter code, a call to the client method is wrapped inside the implementation of the adapter version of the method

Page 45: Design Patterns in Java Chapter 3 Adapter

45

Class and Object Adapters

• The approach illustrated previously is know more specifically as a class adapter

• This is the case where you implement a client interface and extend a service class

• A different approach has to be taken if the client code base does not specify a particular interface

• In this second case it’s necessary to create what is known as an object adapter

Page 46: Design Patterns in Java Chapter 3 Adapter

46

• When implementing an object adapter, the idea is that rather than a Java interface in the client code, there is a class with a set of methods that need to be supported

• The object adapter approach is to make a subclass of the client code class and then make use of an object of the service code base to help implement the methods of the subclass

• Take a look at the following UML diagram

Page 47: Design Patterns in Java Chapter 3 Adapter

47

Page 48: Design Patterns in Java Chapter 3 Adapter

48

• The book describes the object adapter, the NewClass, as adapting by means of delegation

• Observe that NewClass is connected to ExistingClass by means of a navigability arrow

• This means that NewClass has a reference to an object of ExistingClass and can call ExistingClass methods on that object as part of the code implementing the methods in NewClass

• The idea is that the methods in NewClass override the methods in RequiredClass, providing the needed functionality by means of calls on ExistingClass objects

Page 49: Design Patterns in Java Chapter 3 Adapter

49

• Note that the class adapter and object adapter UML diagrams are different

• That is to say, the structure of these two different kinds of adapters is not the same

• However, they are both classified as the adapter pattern because their intent is exactly the same

• They differ structurally because in the adapter case the client provides an interface and in the object case the client provides a class

• It will also become evident later that there are other reasons or cases whether the object adapter is desirable

Page 50: Design Patterns in Java Chapter 3 Adapter

50

• In the previous example, EventSim was the client, and it made use of the predefined RocketSim interface

• This made it possible for the OozinozRocket class to be written to adapt to the existing PhysicalRocket class

Page 51: Design Patterns in Java Chapter 3 Adapter

51

• Now suppose that the EvenSim client is coded to work directly with objects of the class Skyrocket

• The following UML diagram illustrates this basic idea

• Not surprisingly, the Skyrocket class has methods getMass(), getThrust(), and setSimTime()

Page 52: Design Patterns in Java Chapter 3 Adapter

52

Page 53: Design Patterns in Java Chapter 3 Adapter

53

• The foregoing diagram didn’t show the server side, but the idea is similar to what it was before

• There are two ways of stating what you want to do• 1. You want to use the methods of the existing

PhysicalRocket class to support the functionality of the methods of the Skyrocket class

• 2. You want, in one way or another, to be able to run the client code simulation on an object of the PhysicalRocket class

Page 54: Design Patterns in Java Chapter 3 Adapter

54

• Under this scenario, presumably the methods have been implemented for the Skyrocket class

• But we don’t care—we’re going to override them and call methods on a PhysicalRocket object in the overridden versions

• The next UML diagram shows the outline of an object adapter solution to this problem

Page 55: Design Patterns in Java Chapter 3 Adapter

55

Page 56: Design Patterns in Java Chapter 3 Adapter

56

• Before going any further, note the following• If Java supported multiple inheritance, in theory the

OozinozSkyrocket class could be a subclass of both SkyRocket and PhysicalRocket

• In that case, the Class Adapter could more or less be duplicated in solving this problem

• However, multiple inheritance is a mess and Java eschews it

• Therefore, it is necessary to seek an alternative solution

Page 57: Design Patterns in Java Chapter 3 Adapter

57

• Before trying to complete the diagram it is possible to make this observation

• The Class Adapter pattern relied on typing a parameter, for example, to an interface

• The Object Adapter pattern relies on simple polymorphism

• In the client code, a parameter would be typed to the superclass, Skyrocket, and a reference to the subclass, OozinozSkyrocket, could be passed to the client code

Page 58: Design Patterns in Java Chapter 3 Adapter

58

• Note also that the simulation time variable, as in the previous example, has to be dealt with

• Observe that in this most recent diagram, the authors have indicated something which wasn’t shown in the original generic diagram

• Namely, on the client side there is a double instance variable simTime

• It is marked with a # sign, meaning that it’s declared protected• That means that the new subclass under development will

have access to its own simTime instance variable without resorting to a call to a getSimTime() method

Page 59: Design Patterns in Java Chapter 3 Adapter

59

• Challenge 3.3• Complete the class diagram in Figure 3.6 to

show a design that allows OozinozRocket objects to serve as Skyrocket objects.

Page 60: Design Patterns in Java Chapter 3 Adapter

60

Page 61: Design Patterns in Java Chapter 3 Adapter

61

• The critical things to notice in this diagram are the following

• As in the generic picture earlier, there is a navigability arrow from the subclass, the OozinozSkyrocket class, to the object class, the PhysicalRocket class

• In the box representing the OozinozSkyrocket class an instance variable is shown—namely, a reference to an object of the PhysicalRocket class

• It is this object in the subclass that gives the object adapter pattern its name

Page 62: Design Patterns in Java Chapter 3 Adapter

62

• You should also notice that the setSimTime() method doesn’t have to be overridden

• Its implementation in the Skyrocket class is suitable for the subclass and is simply inherited

Page 63: Design Patterns in Java Chapter 3 Adapter

63

• Rather than doing the code of the OozinozSkyrocket class as a challenge, the book simply gives the code

• This shows how an instance of the PhysicalRocket class is created and used to support the needed functionality

• The code follows

Page 64: Design Patterns in Java Chapter 3 Adapter

64

The outset of the OozinozSkyrocket class code.

• package com.oozinoz.firework;• import com.oozinoz.simulation.*;• public class OozinozSkyrocket• extends Skyrocket• {• private PhysicalRocket rocket;

Page 65: Design Patterns in Java Chapter 3 Adapter

65

The book’s constructor for the subclass, which relies on an instance of the PhysicalRocket class being passed in

• public OozinozSkyrocket(PhysicalRocket r)• {• super(r.getMass(0);• r.getThrust(0);• r.getBurnTime());• rocket = r;• }

Page 66: Design Patterns in Java Chapter 3 Adapter

66

• Notice that you are calling methods from the PhysicalRocket class

• Those versions of getMass() and getThrust() take a time parameter

• Not surprisingly, at construction time, the parameter value is time = 0

Page 67: Design Patterns in Java Chapter 3 Adapter

67

• Also notice that in theory you could write the constructor for the subclass to take in the construction parameters for a PhysicalRocket object

• Then instead of passing in an instance of PhysicalRocket, it could be constructed inside the code for the OozinozSkyrocket constructor

• This is not better, just an alternative• One way or the other, the OozinozSkyrocket class has

to end up with a live PhysicalRocket reference inside

Page 68: Design Patterns in Java Chapter 3 Adapter

68

The method implementations in the OozinozSkyrocket class code

• public double getMass()• {• return rocket.getMass(simTime);• }• public double getThrust()• {• return rocket.getThrust(simTime);• }

Page 69: Design Patterns in Java Chapter 3 Adapter

69

Compare the foregoing with the solution in the Class Adapter case:

• public double getMass()• {• return getMass(time);• }• public double getThrust()• {• return getThrust(time);• }

Page 70: Design Patterns in Java Chapter 3 Adapter

70

• In the Class Adapter case you make use of methods inherited from the PhysicalRocket class in order to implement the adapter methods

• In the Object Adapter case, you receive a reference to or create an instance of the PhysicalRocket class and then call methods in the PhysicalRocket class on that object in order to implement the adapter methods

Page 71: Design Patterns in Java Chapter 3 Adapter

71

• Challenge 3.4• Name one reason why the object adapter

design that the OozinozSkyrocket class uses may be more fragile than a class adapter approach.

Page 72: Design Patterns in Java Chapter 3 Adapter

72

• Solution 3.4• The object adapter design that the

OozinozSkyrocket class uses may be more fragile than a class adapter approach for the following reasons.– There is no specification of the interface that the

OozinozSkyrocket class provides. As a result, the Skyrocket might change in ways that would create problems at runtime but go undetected at compile time.

Page 73: Design Patterns in Java Chapter 3 Adapter

73

– The OozinozSkyrocket counts on being able to access the simTime variable of its parent class, although there is no guarantee that this variable will always be declared as protected and no guarantee about the meaning of this field in the Skyrocket class. (We don’t expect the providers to go out of their way to change the Skyrocket code we rely on, but on the other hand, we have limited control over what they do.)

Page 74: Design Patterns in Java Chapter 3 Adapter

74

• The book closes this section by stating that the object adapter approach is riskier than the class adapter approach

• This was suggested by the answers to challenge 3.4• However, you do what you have to do• If no client interface is given, the object adapter works• The book additionally notes that if one of the methods

in the client superclass had been declared final, meaning that it couldn’t be overridden, then we would have been screwed…

Page 75: Design Patterns in Java Chapter 3 Adapter

75

The End?

• The rest of the chapter is on the topic of adapting data for a JTable

• This is an interesting, practical example that arises out of the Java API

• 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 76: Design Patterns in Java Chapter 3 Adapter

76

Adapting Data for a JTable

• There is a class in the Java API, JTable, which is designed to display tables

• The JTable class was written generally, so that it could accept data of various types as table entries

• This was accomplished by providing an interface, TableModel

• In theory, it would be possible to write a class adapter using the TableModel and some application domain class

• The interface is shown on the next overhead

Page 77: Design Patterns in Java Chapter 3 Adapter

77

Page 78: Design Patterns in Java Chapter 3 Adapter

78

• There are several reasons that typically for table data a form of object adapter is preferable

• The first is that the contents of a table likely stem from a collection of domain objects, not from a single class

• Also, it turns out that for many of the methods in the TableModel interface it is possible to provide default implementations

Page 79: Design Patterns in Java Chapter 3 Adapter

79

• The Java API provides an abstract class, AbstractTableModel which includes default implementations of most of the methods in the interface

• This is sort of like an incomplete Java adapter class• The Java API points out the following:• To create a concrete TableModel as a subclass of

AbstractTableModel you need only provide implementations for the following three methods: – public int getRowCount();– public int getColumnCount();– public Object getValueAt(int row, int column);

Page 80: Design Patterns in Java Chapter 3 Adapter

80

• A UML diagram for the AbstractTableModel class is shown on the next overhead

• It indicates the three methods, getColumnCount(), getRowCount(), and getValueAt()

• Presumably these methods are declared abstract in the class

• That’s how come you need to write a concrete subclass that implements them

Page 81: Design Patterns in Java Chapter 3 Adapter

81

Page 82: Design Patterns in Java Chapter 3 Adapter

82

• Now it’s possible to use the Object Adapter design pattern with this class

• In the book’s example, the RocketTableModel class extends the AbstractTableModel class

• The RocketTableModel class implements, among other things, the three needed methods

• It also has an array of instances of the Rocket class which are the source of information for rows in the table

• This is shown in the next diagram

Page 83: Design Patterns in Java Chapter 3 Adapter

83

Page 84: Design Patterns in Java Chapter 3 Adapter

84

• Notice that the UML diagram for the RocketTableModel shows two instance variables, one an array of rockets, another an array of column names

• A constructor is shown for the class which takes an array of rockets as an input parameter

• Also, in addition to the 3 expected methods, an additional method, getColumnName() is shown

Page 85: Design Patterns in Java Chapter 3 Adapter

85

• AbstractTableModel implements the TableModel interface

• By having RocketTableModel extend AbstractTableModel, you are creating an object adapter

• This approach is handy because the RocketTableModel can have a handle on multiple instances of the Rocket class

• Witness the array of rockets instance variable and parameter in the constructor

Page 86: Design Patterns in Java Chapter 3 Adapter

86

• It is also conceptually necessary to have an object adapter rather than a class adapter

• Under the Class Adapter design pattern you would write an adapter which implemented the interface directly and extended the Rocket class

• But this wouldn’t make sense, because the purpose of the adapter in this example is to extract information about more than one rocket

• Such a Class Adapter class would not be a subclass of the Rocket class, as needed in order for that design pattern to be applied

Page 87: Design Patterns in Java Chapter 3 Adapter

87

• The book restates the characteristics of the two kinds of adapters in this way:

• A class adapter subclasses an existing class and implements a target interface

• An object adapter subclasses a target class and delegates to an existing class

• The use of the word delegates is worth remembering• The composition/navigability arrow in the diagram indicates

that the RocketTableModel makes use of multiple instances of the Rocket class

• This is succinctly summarized in the term “delegates”

Page 88: Design Patterns in Java Chapter 3 Adapter

88

• The book finally illustrates the purpose of all of this with a screenshot

• It follows on the next overhead

Page 89: Design Patterns in Java Chapter 3 Adapter

89

Page 90: Design Patterns in Java Chapter 3 Adapter

90

• Next the book gives partial code for an implementation of the RocketTableModel class

• Since the missing pieces are marked “Challenge!” you can predict what comes after the partial code

• The code follows

Page 91: Design Patterns in Java Chapter 3 Adapter

91

• import javax.swing.table.*;• import com.oozinoz.firework.Rocket;

• public class RocketTableModel extends AbstractTableModel

• {• protected Rocket[] rockets;• protected String[] columnNames = new String[]

{ "Name", "Price", "Apogee" };

• public RocketTableModel(Rocket[] rockets)• {• this.rockets = rockets;• }

Page 92: Design Patterns in Java Chapter 3 Adapter

92

• public int getColumnCount()• {• // Challenge!• }

• public String getColumnName(int i)• {• // Challenge!• }

• public int getRowCount()• {• // Challenge!• }

• public Object getValueAt(int row, int col)• {• // Challenge!• }

Page 93: Design Patterns in Java Chapter 3 Adapter

93

• Challenge 3.5• Fill in the code for the RocketTableModel

methods that adapt an array of Rocket objects to serve as a TableModel

Page 94: Design Patterns in Java Chapter 3 Adapter

94

• import javax.swing.table.*;• import com.oozinoz.firework.Rocket;

• public class RocketTableModel extends AbstractTableModel {

• protected Rocket[] rockets;• protected String[] columnNames = new String[]

{ "Name", "Price", "Apogee" };

• public RocketTableModel(Rocket[] rockets)• {• this.rockets = rockets;• }

Page 95: Design Patterns in Java Chapter 3 Adapter

95

• public int getColumnCount()• {• return columnNames.length;• }

• public String getColumnName(int i)• {• return columnNames[i];• }

• public int getRowCount()• {• return rockets.length;• }

Page 96: Design Patterns in Java Chapter 3 Adapter

96

• public Object getValueAt(int row, int col)• {• switch (col)• {• case 0:• return rockets[row].getName();• case 1:• return rockets[row].getPrice();• case 2:• return new Double(rockets[row].getApogee());• default:• return null;• }• }

Page 97: Design Patterns in Java Chapter 3 Adapter

97

• The book provides example application code which uses the RocketTableModel adapter

• In this code, instances of Rocket are created and placed in an array

• An instance of RocketTableModel is constructed with the rocket array passed in as a parameter

• Swing classes are used to display the table• Code for this example application follows

Page 98: Design Patterns in Java Chapter 3 Adapter

98

• import java.awt.Component;• import java.awt.Font;• import javax.swing.*;• import com.oozinoz.firework.Rocket;• import com.oozinoz.utility.Dollars;

• public class ShowRocketTable• { • public static void main(String[] args)• {• setFonts();• JTable table = new JTable(getRocketTable());• table.setRowHeight(36);• JScrollPane pane = new JScrollPane(table);• pane.setPreferredSize(new java.awt.Dimension(300, 100));• display(pane, " Rockets");• }•

Page 99: Design Patterns in Java Chapter 3 Adapter

99

• public static void display(Component c, String title)• {• JFrame frame = new JFrame(title);• frame.getContentPane().add(c);• frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); • frame.pack();• frame.setVisible(true);• }

• private static RocketTableModel getRocketTable()• {• Rocket r1 = new Rocket("Shooter", 1.0, new Dollars(3.95), 50.0, 4.5);• Rocket r2 = new Rocket("Orbit", 2.0, new Dollars(29.03), 5000, 3.2);• return new RocketTableModel(new Rocket[] { r1, r2 });• }

• private static void setFonts()• {• Font font = new Font("Dialog", Font.PLAIN, 18);• UIManager.put("Table.font", font);• UIManager.put("TableHeader.font", font);• }

Page 100: Design Patterns in Java Chapter 3 Adapter

100

• The book sums up this example in this way• The ShowRocketTable class is a short

application that can show rocket information in an instance of JTable

• It can be short and sweet because of the existence of the TableModel interface, the AbstractTableModel class, and the RocketTableModel class which extends the abstract class

Page 101: Design Patterns in Java Chapter 3 Adapter

101

• The RocketTableModel implements the object adapter design pattern

• It has instances of the Rocket class in it• It is information about these instances of the Rocket class

that is used to fill the rows of the JTable generated by the ShowRocketTable application

• In other words, the JTable class can’t know in advance which of the many types of data an application may wish to display in its cells

• The adapter design adapts rocket data for display in a JTable

Page 102: Design Patterns in Java Chapter 3 Adapter

102

Identifying Adapters

• Consider the following UML diagram for the Java MouseAdapter class, and the challenge that follows it

Page 103: Design Patterns in Java Chapter 3 Adapter

103

Page 104: Design Patterns in Java Chapter 3 Adapter

104

• Challenge 3.6• Are you applying the Adapter pattern when

you use the MouseAdapter class? Explain how (or why not).

Page 105: Design Patterns in Java Chapter 3 Adapter

105

• Solution 3.6• One argument: When the user clicks the

mouse, I need to translate, or adapt, the resulting Swing call into an appropriate action. In other words, when I need to adapt GUI events to my application’s interface, I use Swing adapter classes. I am translating from one interface to another, fulfilling the intent of the Adapter pattern.

Page 106: Design Patterns in Java Chapter 3 Adapter

106

• A counterargument: The “adapter” classes in Swing are stubs: They don’t translate or adapt anything. You subclass these classes, overriding the methods you need to do something. If anything, it is your methods and your class that form an example of Adapter. Had the Swing “adapter” been named something like DefaultMouseListener, this argument never would have arisen.

Page 107: Design Patterns in Java Chapter 3 Adapter

107

Summary

• A class adapter implements an interface and extends a class in order to adapt the class to the interface

• An object adapter extends a class and makes use of objects in order to adapt the objects to the class

• JTable, TableModel, and AbstractTableModel provide examples of an adapter pattern in the Java API

• For practical and conceptual reasons, the table example is an example of an object adapter

• If you have a grip on the basic idea underlying adapters, you may be able to use them in your own code

Page 108: Design Patterns in Java Chapter 3 Adapter

108

The End