Download presentation
Presentation is loading. Please wait.
1
Chapter 3 Adapter Summary prepared by Kirk Scott 1
2
Whimbrel From 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.waderScolopacidaecurlewssubarcticNorth AmericaEurope AsiaScotland 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.migratory AfricaSouth AmericaAsiaAustralasiamigration [2] 2
3
3
4
Godwit From Wikipedia, the free encyclopedia Jump to: navigation, search For other uses, see Limosa (disambiguation).navigationsearchLimosa (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]migratorywadersbirdgenusmolluscs [1] 4
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.curlewsdowitchers 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."Thomas Browne The name Godwit originates in Old English with god meaning good, and wit coming from wihte, meaning creature. [2] [2] 5
6
6
7
7
8
Curlew From Wikipedia, the free encyclopedia Jump to: navigation, search For other uses, see Curlew (disambiguation). For other uses of "Numenius", see Numenius.navigationsearchCurlew (disambiguation)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./ˈkɜrljuːz/genusbirdsplumagescolopacid wadersgodwits [1]EuropeEurasian Curlew 8
9
9
10
Design Patterns in Java Chapter 3 Adapter Summary prepared by Kirk Scott 10
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 11
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 12
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 13
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 14
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 15
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 16
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 17
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 18
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 19
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 20
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 21
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 22
23
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 24
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 25
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 26
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 27
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 28
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() 29
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 30
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 31
32
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 33
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 34
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 35
36
Challenge 3.1 Solution 36
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 37
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 38
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 39
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 40
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; 41
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; } 42
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); } 43
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 44
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 45
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 46
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 47
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 48
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 49
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 50
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 51
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 52
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 53
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 54
55
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 56
57
The form of delegation in the adapter class is illustrated by this snippet of code: requiredMethod() { … existingClassObjectReference.usefulMethod(); … } 57
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 58
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 59
60
UML for the Client Side 60
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 61
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 62
63
As usual, the book does things in stages The UML diagram given on the next overhead shows the book’s complete design 63
64
Solution 3.4 64
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 65
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 66
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 67
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 68
69
The beginning of the OozinozSkyrocket class code. package com.oozinoz.firework; import com.oozinoz.simulation.*; public class OozinozSkyrocket extends Skyrocket { private PhysicalRocket rocket; 69
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; } 70
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 71
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 72
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 73
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); } 74
75
Compare the foregoing with the solution in the Class Adapter case: public double getMass() { return getMass(time); } public double getThrust() { return getThrust(time); } 75
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 76
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.” 77
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] 78
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.] 79
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.)” 80
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 81
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 82
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 83
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 84
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 85
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 86
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 87
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.” 88
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 89
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 90
91
91
92
Challenge 3.6 “Are you applying the Adapter pattern when you use the MouseAdapter class? Explain how (or why not).” 92
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. 93
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.” 94
95
On the following overhead a UML diagram is given It may be helpful in understanding the foregoing discussion. 95
96
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 97
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 98
99
This is a small example of a table containing information about specific kinds of rockets 99
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 100
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 101
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 102
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 103
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 104
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 105
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 106
107
107
108
108
109
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 110
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 111
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 112
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 113
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 114
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 115
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 116
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 117
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 118
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 119
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 120
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 121
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 122
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 123
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 124
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); 125
126
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 127
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 128
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 129
130
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 131
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 132
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 133
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 134
135
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 136
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; } 137
138
public int getColumnCount() { return columnNames.length; } public String getColumnName(int i) { return columnNames[i]; } public int getRowCount() { return rockets.length; } 138
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; } 139
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 140
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"); } 141
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); } 142
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 143
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 144
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 145
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 146
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 147
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? 148
149
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 150
151
The End 151
Similar presentations
© 2024 SlidePlayer.com. Inc.
All rights reserved.