Chapter 3 Adapter Summary prepared by Kirk Scott 1

Preview:

Citation preview

1

Chapter 3Adapter

Summary prepared by Kirk Scott

2

WhimbrelFrom Wikipedia, the free encyclopedia

• The Whimbrel (Numenius phaeopus) is a wader in the large family Scolopacidae. It is one of the most widespread of the curlews, breeding across much of subarctic North America, Europe and Asia as far south as Scotland.

• This is a migratory species wintering on coasts in Africa, South America, south Asia into Australasia and southern North America. It is also a coastal bird during migration.[2] It is fairly gregarious outside the breeding season.

3

4

GodwitFrom Wikipedia, the free encyclopedia

• Jump to: navigation, search For other uses, see Limosa (disambiguation).

• The godwits are a group of large, long-billed, long-legged and strongly migratory waders of the bird genus Limosa. Their long, bills allow them to probe deeply in the sand for aquatic worms and molluscs. They frequent tidal shorelines, breeding in northern climates in summer and migrating south in winter. In their winter range, they flock together where food is plentiful. A female Bar-tailed Godwit holds the record for the longest non-stop flight for a land bird.[1]

5

• They can be distinguished from the curlews by their straight or slightly upturned bills, and from the dowitchers by their longer legs. The winter plumages are fairly drab, but three species have reddish underparts when breeding. The females are appreciably larger than the males.

• Although not common tablefare today, they were once a popular British dish. Sir Thomas Browne writing in the seventeenth century noted that godwits "were accounted the daintiest dish in England."

• The name Godwit originates in Old English with god meaning good, and wit coming from wihte, meaning creature.[2]

6

7

8

CurlewFrom Wikipedia, the free encyclopedia

• Jump to: navigation, search For other uses, see Curlew (disambiguation).For other uses of "Numenius", see Numenius.

• The curlews /ˈkɜrljuːz/, genus Numenius, are a group of eight species of birds, characterised by long, slender, downcurved bills and mottled brown plumage. They are one of the most ancient lineages of scolopacid waders, together with the godwits which look similar but have straight bills.[1] In Europe "curlew" usually refers to one species, the Eurasian Curlew Numenius arquata.

9

10

Design Patterns in JavaChapter 3Adapter

Summary prepared by Kirk Scott

11

Introduction Before the Introduction

• The adapter design pattern is fundamental• One of my jokes is that once you’ve seen the

adapter pattern, every pattern after it can be described as a kind of adapter

• The pattern allows one class to “make use of” another

12

• Structurally, there are two different implementations of the pattern

• The Class Adapter is based on an interface and a subclass

• The Object Adapter is based on a subclass and a wrapped instance of another class

13

Introduction to the Class Adapter

• Consider these possible scenarios in the development of client and service code which need to work together

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

• Or, the client code may be written before the service code

14

• Or, code bases may belong to different organizations which happen to define different interfaces for the same functionality

• In any of these scenarios, the client code may make calls to methods that do not end up in the service code

15

• The ultimate goal is for the client and server to work together in spite of the mismatch

• In order for this to happen, at the very least the needed functionality has to exist in the service code, even if it is behind a different interface

16

• You may consider rewriting either the client or the service code so that their naming conventions match

• However, this may not be possible for political or timing reasons

• Even if possible, recoding may be undesirable because it’s too much work

17

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

• 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

18

Book Definition of Pattern

• Book definition:• The intent of Adapter is to provide the

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

19

The Class Adapter: Adapting to an Interface

• In the ideal case, client and service code are simply written to be consistent with each other

• If the client code is written first, the client developer may create an interface which defines all of the calls the client will need to make

• Then the service code developer can have the service classes implement that interface

20

• In the less than ideal case, the service code is not written to the desired interface

• However, such an interface, defining what the client needs, can be used to apply the class adapter design pattern

• The adapter class, which connects the client with the service code, will implement this interface

21

• The adapter class will also extend 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

22

• The diagram on the following overhead illustrates a class adapter

• Note that for this pattern a UML diagram can be given right away

• The pattern is immediately apparent from the diagram

23

24

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

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

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

• The implementation of requiredMethod() in NewClass is based on calls to usefulMethod() in ExistingClass

25

Using the Class Adapter in Practice

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

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

• This notation in UML can mean that the client has an instance variable of the type referred to

26

• This notation can also mean that the client has a reference to something with that type which isn’t an instance variable

• For example, the client may have a parameter of that typed passed to it

27

Interface References to Objects

• Either way, the critical idea is this:• The client code is written with references to

the interface, not references to specific classes• An object of any class that implements the

interface can be passed to the client and used by it

28

• This is a simple, but very important idea• In CS 202 you learn about superclass

references to subclass objects• Here you are seeing interface references to

objects of classes that implement the interface

29

Implementation of Adapter Methods

• The client will be written to call the method requiredMethod(), but not on a direct reference to a NewClass object

• The client will be written to call the method requiredMethod() in this way:

• requiredInterfaceReference.requiredMethod()

30

A More Concrete Example

• The book gives an example of a class adapter using rockets

• The example will center on two methods relevant to the performance of rockets during flight, getMass() and getThrust()

• The mass and thrust of a rocket are dependent on time

• Over the course of a flight, as fuel is burnt, mass goes down, and at some point the rocket achieves maximum thrust

31

The Structure of the Example

• The example begins with two parts:• EventSim, a rocket simulation program, the

client• RocketSim, the interface for rockets used by

the client• A UML diagram for this is shown on the

following overhead

32

33

• The example also has a PhysicalRocket class which represents rockets

• The goal is to run EventSim and apply it to instances of the PhysicalRocket class

• The PhysicalRocket class methods are not exactly the same as the methods in the RocketSim interface

34

• The methods in the class PhysicalRocket parallel the functionality of the methods in the RocketSim interface

• The names of the methods in the interface and the class are the same, but their parameter lists differ

• The PhysicalRocket class has to be adapted to the RocketSim interface

35

• The PhysicalRocket class is adapted to the RocketSim interface in this way:

• You write a new, adapter class, OozinozRocket, which implements the interface and extends the class.

• The book does this in steps, as a challenge• The UML diagram on the following overhead

cuts to the chase

36

Challenge 3.1 Solution

37

• The adapter class has to deal with the mismatch in the specifications between the adapter interface and the class to be adapted

• The getMass() and getThrust() methods take no parameter in the RocketSim interface

• They take a time parameter in the PhysicalRocket class

38

• There is a setSimTime() method in the RocketSim interface

• RocketSim keeps an internal clock and occasionally updates simulated objects by calling the setSimTime() method

• The adapter class implements this method and provides the instance variable needed for it

39

• This instance variable makes it possible for the adapter to make use of the base class methods

• An adapter method which doesn’t take a time parameter is implemented by calling a service class method that does take a time parameter

• The adapter method passes in the time instance variable when calling the service class method

40

• The adapter class, OoozinozRocket, inherits methods from the PhysicalRocket class

• These inherited methods are used in implementing the interface methods

• The following overheads show the code solution for the adapter class

• As usual, the book does this as a challenge• The solution is simply presented here

41

Solution 3.2

• package com.oozinoz.firework;• import com.oozinoz.simulation.*;• public class OozinozRocket• extends PhysicalRocket• implements RocketSim• {• /*** The adapter class has this instance variable. ***/

• private double time;

42

• public OozinozRocket• (double burnArea, double burnRate,• double fuelMass, double totalMass)• {• super(burnArea, burnRate,• fuelMass, totalMass);• }• /*** The adapter class also has this set method

for the needed variable. ***/• public void setSimTime(double time)• {• this.time = time;• }

43

• /*** With the variable available, it’s a piece of cake to implement these methods. ***/

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

44

More Comments on the Code

• The time instance variable provides the parameter needed in order to call the service class methods

• It is apparent that the client side developer, when specifying the interface, knew that a time variable would be necessary

• That accounts for the inclusion of setSimTime() in the interface

45

• 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

46

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

• The client code only calls these versions• The service code versions of the methods do

have a time parameter• In the adapter class code, a call to the service

method—with a time parameter—is wrapped inside the implementation of the interface version of the method

47

Simplicity/Complexity

• The example is simple• It’s so simple that you may overlook what is

happening• When you call one version of a method, that is

delegated to another version of the same method

• The call is passed on, and that call is made on the implicit parameter

48

• The adapter for the client side has get methods that don’t take a time parameter

• They assume that the needed time is passed in with a call to setSimTime()

• The service class actually has methods that take the needed time parameter

49

• You might think if mass and thrust depend on time, then the client side code might have been written with method calls which passed time as a parameter

• But setting the simulation time separately is an equally valid way of making the time available

50

• If time is made available in this way, then in the client code:

• You would have to pay careful attention to when you had called setSimTime() before calling either getMass() or getThrust()

• The return values of the get calls will depend on the most recent value of simTime that was sent in

51

Introduction to the Object Adapter

• Suppose that the client code base does not specify a particular interface

• Instead, it has been coded to use the methods of a particular class

• Suppose that a different class exists in the service code which provides the necessary functionality

52

• An object adapter is a class which extends the class specified in the client and wraps an instance of the service class

• The adapter derives the needed functionality from the wrapped instance

• In other words, the methods in the adapter class work by calling methods on the wrapped object

53

• This way of doing things is expressed by the term “delegation”

• The object adapter delegates responsibility for the actual functionality desired to the instance of the service class it contains

• The adapter class adapts an instance of the service class for use by the client by providing an appropriate interface for it

54

• The diagram on the following overhead illustrates an object adapter

• Note that for this pattern, just like for a class adapter, a UML diagram can be given right away

• The pattern is immediately apparent from the diagram

55

56

• The adapter class is connected to the useful class by means of a navigability arrow

• The adapter class contains a reference to a useful class instance variable

• The adapter class implements the interface needed by the client

• It does so by making calls to methods on the useful object

57

• The form of delegation in the adapter class is illustrated by this snippet of code:

• requiredMethod()• {• …• existingClassObjectReference.usefulMethod();• …• }

58

• The structures of the class and object adapters are not the same

• However, both are valid adapters• Their intent and functional effect are the same

59

A More Concrete Example

• Suppose that the EventSim client is coded to work directly with references to objects of a class named Skyrocket

• The Skyrocket class has methods getMass(), getThrust() which do not take a time parameter

• It also has a setSimTime() method• The UML diagram shown on the following

overhead illustrates this idea

60

UML for the Client Side

61

The Service Side of the Example

• The service side of the application is similar to the previous scenario

• There is a PhysicalRocket class that implements the desired functionality

• You want to use the methods of the PhysicalRocket class to support the functionality of the methods of the Skyrocket class on the client side

62

The Adapter Class

• The adapter class will be a subclass of the client side SkyRocket class

• The adapter class will have a PhysicalRocket instance variable

• The adapter class will override the methods, delegating to the PhysicalRocket it contains

63

• As usual, the book does things in stages• The UML diagram given on the next overhead

shows the book’s complete design

64

Solution 3.4

65

Things to Note in the Diagram

• You might note that if there were such a thing, multiple inheritance would be an approach to solving the problem

• In the class adapter you implement an interface on the client side and extend a class on the service side

• Here, you extend a class on the client side• You can’t also extend the class on the service side• Instead, you have to wrap an instance

66

• The simulation time variable, as in the class adapter example, is at the heart of what you will have to do in your implementation

• In the SkyRocket class there is a double instance variable simTime and a setSimTime() method

• In this example these are inherited by the adapter subclass

67

• The simTime variable is marked with a # sign, meaning that it’s declared protected

• That means that the adapter subclass will have direct access to its own simTime instance variable without calling a get method

• This is not a design decision that I would prefer

• It will be discussed further later on

68

Code for the Object Adapter Example

• The object adapter class has to obtain a reference to a PhysicalRocket object

• The object adapter class also has to override getMass() and getThrust()

• The book’s code is presented on the following overheads with commentary

69

The beginning of the OozinozSkyrocket class code.

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

70

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;• }

71

• The constructor for the object adapter relies on a call to super in the superclass on the client side, Skyrocket

• The superclass constructor requires values for mass and thrust

• This is the first example of wrapping• The needed values are acquired by calling getMass() and

getThrust() on the input parameter, the PhysicalRocket• Because this is initialization, time t = 0 is used• The call to super has to come first• Then you can initialize the instance variable, r

72

An Alternative Approach

• You could also write the constructor for the subclass to take in the construction parameters for a PhysicalRocket object

• Then the OozinozSkyrocket constructor would construct an instance of PhysicalRocket instead of receiving one as a parameter

• This is not better, just an alternative• One way or the other, the instance of the object

adapter class, OozinozSkyrocket, has to end up with a live PhysicalRocket reference inside it

73

Using the Object Adapter in Practice

• The Object Adapter pattern works because of straightforward polymorphism

• You can have a superclass reference to a subclass object

• In the client code, a parameter would be typed to the superclass, Skyrocket, for example

• A reference to the adapter subclass, OozinozSkyrocket, could then be passed to the client code

74

The method implementations in the OozinozSkyrocket object adapter class code

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

75

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

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

76

• In the Class Adapter case you call methods inherited from the PhysicalRocket class on the implicit parameter in order to implement the adapter methods

• In the Object Adapter case, you call methods on an instance of the PhysicalRocket class in order to implement the adapter methods

• In both cases the conversion is from a method that takes a time parameter to one that doesn’t

77

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

78

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

• [see the following overheads]

79

• [1] 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.

• [Comments will follow.]

80

• [2] 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.)”

81

Comments on Fragility Number 2

• Comment mode on:• I want to deal with “fragility” number 2 first:• This is the kind of nonsense that makes you want to

bellow in revulsion and disbelief• The instance variable should be declared private,

not protected• This has nothing to do with the design pattern, and

the fact that they identify this as a shortcoming is merely an argument against their own lame coding practices

82

Comments on Fragility Number 1

• Regarding “fragility” number 1, the premise seems to be the following:

• In the class adapter pattern, you specify the desired interface

• Presumably, having made the specification, it is something that is unlikely to change

83

• The authors assume that the specifications of the Skyrocket class may be subject to change

• On the one hand, you might ask whether this is more changeable than an interface

• At any rate, they then observe that the changes might cause problems that the compiler wouldn’t catch and which would only be evident at run time

84

• How might this happen?• The superclass has its instance variables and

methods changed• The subclass inherits all of the changes, but—• It still includes the methods developed earlier• These methods may still override methods in the

superclass• If the superclass methods are gone, then the

methods in the subclass are simply independent

85

• The bottom line is that the set of methods in the subclass may no longer appropriately perform adaptation

• The fundamental moral of the story is this:• If you develop a hierarchy of classes and you

make a change in a superclass, you need to trace down through all of its subclasses to see whether or not they are still OK

86

• This fundamental design and coding principle applies whether you’re talking about adapters or not

• If you can safely assume that a specified interface is unlikely to change, then the class adapter pattern is not liable to this problem

• On the other hand, if the interface specification does change, you face a similar situation

87

• You would have to look at every class that implemented the interface to make sure that the implementation matched the new specification

• The difference is that the compiler would detect classes that declared that they implemented the interface but which no longer conformed to the interface specifications

88

Final Methods and Adaptation

• The book makes another observation about the applicability of the object adapter

• If one of the methods in the client superclass had been declared final it couldn’t be overridden in a subclass

• Then the the object adapter approach wouldn’t work

• There are always potential problems• Dirty Harry says, “Know your limitations.”

89

Choosing between Class and Object Adapters

• The book suggests that the class adapter is preferable to the object adapter

• However, you do what you have to do• If no client interface is given, the object

adapter approach works• The next example will illustrate a situation

where object adaptation is the correct approach for several reasons

90

Are Java Adapter Classes the Same as the Adapter Design Pattern?

• The answer to this question is basically “no”• The book covers it in some detail, and for

what it’s worth, that treatment is repeated here

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

91

92

• Challenge 3.6• “Are you applying the Adapter pattern when

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

93

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

94

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

95

• On the following overhead a UML diagram is given

• It may be helpful in understanding the foregoing discussion.

96

97

Another Example

• In the units so far “Another Example” has been something developed by me with cups and seeds or something like that

• In this unit the other example is taken from the chapter in the book

• This is another example (like façade) where the book identifies the use of a design pattern in the Java API

98

The Scenario

• The scenario involves displaying data in tabular form• An application may contain instances of a given

class• That class would have a set of instance variables• This would be a logical way of displaying

information about objects of the class:• Create a table with one row for each object• The columns would contain the values of the

instance variables for each object

99

• This is a small example of a table containing information about specific kinds of rockets

100

Adapting Data for a JTable

• The machinery in the Java API for the application of the adapter design pattern to this scenario includes these components:

• The client class: JTable• An interface: TableModel• An abstract class: AbstractTableModel

101

JTable

• JTable is the basic building block in the Java API for the use of the pattern

• JTable contains the functionality for displaying data in tabular form

• You would write an application that created and used a JTable, relying on JTable to display the table

102

• JTable is not the adapter in this example• JTable is the client, and the application

containing it is the client of the client, so to speak

• You need the adapter pattern to adapt instances of the class to be displayed as sources for input to a JTable

103

An Interface: TableModel

• The application of the adapter pattern in the Java API involves the use of an interface, TableModel

• However, this example illustrates object adaptation, not class adaptation

• There is an interface because the application of the pattern is slightly more complicated than the initial examples of adaptation given earlier

104

An Abstract Class: AbstractTableModel

• There is also an abstract class in the application of the pattern

• This did not exist in either of the two simple examples of adaptation

• The AbstractTableModel class is provided as a superclass for concrete classes which will be the adapters for object adaptation

105

UML for Table Adaptation

• On the following three overheads a sequence of UML diagrams is given

• This sequence traces the example from the JTable class, the client, through the interface and abstract class to the following:

• A concrete RocketTableModel adapter class, a subclass of the AbstractTableModel class

106

• The RocketTableModel class is an object adapter

• It contains an array of references to instances of the Rocket class

• It is the data for individual rockets whose data should populate the table

• The RocketTableModel class does object adaptation of rocket objects to the requirements for a row in a table

107

108

109

110

JTable, Again

• The class JTable is designed to display information in tables

• The JTable class was written to accept as input things that implement the TableModel interface

111

TableModel, Again

• The TableModel interface defines the set of methods which a class should have in order to be displayable in a JTable

• Rather than putting the specifications for the adapting class into a class, the Java API designers put them into an interface

112

AbstractTableModel, Again

• The AbstractTableModel implements the TableModel interface

• To use JTable the programmer has to write a concrete class that extends AbstractTableModel

• JTable will make use of instances of this concrete class wherever it has references to the TableModel interface

113

• The concrete class that extends AbstractTableModel is an object adapter

• It should contain and adapt one or more references to base objects which are to be displayed in the table

114

Why Object Adaptation?

• There are several reasons for using an object adapter arrangement like this for tables

• 1. It’s convenient to have the AbstractTableModel class on the client side instead of an interface

• This makes it possible to provide default implementations of methods

115

• Only if necessary will those methods be overridden in the concrete subclass

• Notice how this is in general a direct argument in favor of object adaptation

• In a previous section object adaptation was criticized as fragile

• In its favor, it does support inheritance rather than implementation from scratch for an interface

116

• 2. There is a second reason why object adaptation might be better than class adaptation in some situations

• This has to do with a fundamental question in object-oriented design

• The example does class adaptation between tables and rockets

117

• We will have a class, RocketAdapter, which implements the TableModelInterface and extends the Rocket class

• Even though RocketAdapter extends the Rocket class, implementing the interface turns out to be the defining characteristic of the adapter

118

• Client code only calls adapter interface methods on objects of the adapter class

• The client doesn’t call rocket specific methods on those objects, even though they inherit them

• Any calls that do involve rocket specific features are delegated through interface calls

119

• From the client code’s perspective, the adapter quacks like a table model and walks like a table model

• In other words, in a sense the adapter class becomes “a kind of” the TableModel, not a kind of rocket

• Rational object-oriented design says that if something is no longer a kind of something else, then structurally, it shouldn’t be a subclass of that other class

120

• Therefore, if you were using the class adapter version of the pattern it would not be logically desirable for the class that implemented the interface to be a subclass of the Rocket class

• The logical alternative is to use the object adapter version of the pattern

121

• The Java API does use object adaptation• In the example, the adapter is named

RocketTableModel• It is not named RocketAdapter• This is because the adapter has more to do

with tables than with rockets

122

Why Object Adaptation, Again

• Everything said above could be said to apply more or less in general

• Whether object adaptation is really preferable depends on the problem domain

• In the initial example it was a rocket simulator and rockets

• There it seemed perfectly logical for the simulator to work with adapted rockets

123

• With tables, the difference between JTable and rocket is great

• Here it makes sense for the client to work not with rockets, but with an adapter which is really a table model

• The table model essentially wraps the “foreign” item, rocket, completely, and JTable only has to worry about generic things like data items, not specific rocket attributes

124

Specifics on AbstractTableModel

• The Java API contains the abstract class, AbstractTableModel

• This class includes default implementations of most of the methods in the TableModel interface

• The Java API is trying to do some of the work for the programmer wanting to use JTable

125

• A UML diagram of the AbstractTableModel class is shown on the following overhead

• This shows the three methods that a concrete subclass has to override: – public int getRowCount();– public int getColumnCount();– public Object getValueAt(int row, int column);

126

127

• The implementation of the methods depends on what is being adapted

• In particular, these methods presuppose that the adapter has references to multiple objects with multiple attributes

128

• The row count would depend on how many rockets the adapter had a reference to

• The column count would depend on how many of the attributes of a rocket were to be displayed in the table

• getValueAt() would obtain the contents of a cell of the table

129

Specifics of RocketTableModel

• The RocketTableModel class is the programmer written adapter class in this example

• It extends the AbstractTableModel class• The RocketTableModel class implements the

three needed methods• It also implements a getColumnName() method,

among other things• The UML diagram showing this is shown again on

the following overhead

130

131

• The RocketTableModel has an instance variable which is an array of rockets

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

• Each element of the rocket array will become a row in the table

• Each column in a row will take its value from one of the instance variables of a rocket

132

• The RocketTableModel also has an instance variable which is an array of column names

• Each column heading will take its value from an element in the array of column names

133

Why Object Adaptation, for the Last Time

• The fact that the adapter adapts an array of rockets dictates the use of an object adapter

• The adapter class could not logically be a “subclass of an array of rockets” as it would have to be if it were a class adapter

• It is an object adapter that adapts to a collection of data objects

• This is necessary because what you’re adapting to, a table, has multiple entries

134

The Desired Result

• The purpose of all the machinery is to be able to display rocket information in a table

• The screenshot illustrating this result is shown again on the following overhead

135

136

Partial Code for the RocketTableModel Class

• As usual, the code for the solution to the problem is given as a challenge

• Instead, the complete code is given on the following overheads

137

• 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;• }

138

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

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

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

139

• 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;• }• }

140

An Example of Using the RocketTableModel Adapter

• 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

141

• 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");• }•

142

• 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);• }

143

Summarizing the Example

• 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

144

• 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

145

Why JTable and the Pattern?

• When the JTable is created, an instance of the concrete model class is passed to it

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

146

• The model contains the needed information, and the JTable code can obtain it from the model

• All we have to do is implement the needed methods in the concrete model because calls internal to the JTable rely on those methods

147

• The Java API makes use of the object adapter design pattern in order to make it easy to display object data in a table

• The example code could easily be rewritten to make an adapter for any kind of object that you’d like to display in a table

• The burden of creating the table itself is removed from the programmer

148

A UML Diagram for the Pattern from Lasater

• Lasater’s UML diagram is given on the next overhead.

• Which of the two adapter patterns is shown?

149

150

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

• The Java API makes use of adaptation in order to create tables of data

151

The End