- Adapting to an Interface
- Class and Object Adapters
- Adapting Data for a JTable
- Identifying Adapters
- Summary
Adapting Data for a JTable
A common example of an object adapter comes when you want to display data in a table. Swing provides the JTable widget to display tables. Obviously, the designers of this widget didn’t know what data you would want to display. Rather than hard-code some data structure into the widget, they provided an interface, TableModel. JTable does its work in terms of this interface. You then provide an adapter that makes your data conform to the TableModel. See Figure 3.7.
Figure 3.7 The JTable class is a Swing component that displays data from an implementation of TableModel into a GUI table.
Many of the methods in TableModel suggest the possibility of a default implementation. Fortunately, the Java Development Kit (JDK) supplies an abstract class that provides default implementations of all but the most domain-specific methods in TableModel. Figure 3.8 shows this class.
Figure 3.8 The AbstractTableModel class provides defaults for all but a few of the methods in TableModel.
Suppose that you want to show a few rockets in a table, using a Swing user interface. As Figure 3.9 shows, you can create a RocketTableModel class that adapts an array of rockets to the interface that TableModel expects.
Figure 3.9 The RocketTableModel class adapts the TableModel interface to the Rocket class from the Oozinoz domain.
The RocketTableModel class has to subclass AbstractTableModel because AbstractTableModel is a class, not an interface. Whenever the interface you are adapting to is supported with an abstract class that you want to use, you must use an object adapter. In this instance, a second reason you do not want to use a class adapter is that a RocketTableModel is not a kind or a subtype of Rocket. When an adapter class must draw on information from more than one object, you will usually implement it as an object adapter.
Note the difference: 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.
Once you create the RocketTableModel class, you can easily display information about rockets in a Swing JTable object, as Figure 3.10 shows.
Figure 3.10 An instance of JTable fueled with rocket data
package app.adapter; 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; } public int getColumnCount() { // Challenge! } public String getColumnName(int i) { // Challenge! } public int getRowCount() { // Challenge! } public Object getValueAt(int row, int col) { // Challenge! } }
To launch the display that Figure 3.10 shows, you can create a couple of example rocket objects, place them in an array, construct an instance of RocketTableModel from the array, and use Swing classes to display the table. The ShowRocketTable class provides an example:
package app.adapter; 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"); } 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); } }
With fewer than 20 statements of its own, the ShowRocketTable class sits above thousands of statements that collaborate to produce a table component within a graphical user interface (GUI) framework. The JTable class can handle nearly every aspect of displaying a table but can’t know in advance what data you will want to present. To let you supply the data it needs, the JTable class sets you up to apply Adapter. To use JTable, you implement the TableModel interface that JTable expects, along with a class that provides the data you want to display.