- Adapting to an Interface
- Class and Object Adapters
- Adapting Data for a JTable
- Identifying Adapters
- Summary
Class and Object Adapters
The designs in Figures 3.1 and 3.3 are class adapters that adapt through subclassing. In a class adapter design, the new adapter class implements the desired interface and subclasses an existing class. This approach will not always work, notably when the set of methods that you need to adapt is not specified in an interface. In such a case, you can create an object adapter—an adapter that uses delegation rather than subclassing. Figure 3.4 shows this design. (Compare this to the earlier diagrams.)
Figure 3.4 You can create an object adapter by subclassing the class that you need, fulfilling the required methods by relying on an object of an existing class.
The NewClass class in Figure 3.4 is an example of Adapter. An instance of this class is an instance of the RequiredClass class. In other words, the NewClass class meets the needs of the client. The NewClass class can adapt the ExistingClass class to meet the client’s needs by using an instance of ExistingClass.
For a more concrete example, suppose that the simulation package worked directly with a Skyrocket class, without specifying an interface to define the behaviors that the simulation needs. Figure 3.5 shows this class.
Figure 3.5 In this alternative design, the com.oozinoz.simulation package does not specify the interface it needs for modeling a rocket.
The Skyrocket class uses a fairly primitive model of the physics of a rocket. For example, the class assumes that the rocket is entirely consumed as its fuel burns. Suppose that you want to apply the more sophisticated physical model that the Oozinoz PhysicalRocket class uses. To adapt the logic in the PhysicalRocket class to the needs of the simulation, you can create an OozinozSkyrocket class as an object adapter that subclasses Skyrocket and that uses a PhysicalRocket object, as Figure 3.6 shows.
Figure 3.6 When completed, this diagram will show an object adapter design that uses information from an existing class to meet the needs that a client has of a Skyrocket object.
As an object adapter, the OozinozSkyrocket class subclasses from Skyrocket, not PhysicalRocket. This will allow an OozinozSkyrocket object to serve as a substitute wherever the simulation client needs a Skyrocket object. The Skyrocket class supports subclassing by making its simTime variable protected.
The code for the OozinozSkyrocket class might be as follows:
package com.oozinoz.firework; import com.oozinoz.simulation.*; public class OozinozSkyrocket extends Skyrocket { private PhysicalRocket rocket; public OozinozSkyrocket(PhysicalRocket r) { super( r.getMass(0), r.getThrust(0), r.getBurnTime()); rocket = r; } public double getMass() { return rocket.getMass(simTime); } public double getThrust() { return rocket.getThrust(simTime); } }
The OozinozSkyrocket class lets you supply an OozinozSkyrocket object anywhere that the simulation package requires a Skyrocket object. In general, object adapters partially overcome the problem of adapting an object to an interface that is not expressly defined.
The object adapter for the Skyrocket class is a riskier design than the class adapter that implements the RocketSim interface. But we should not complain too much. At least no methods were marked final, which would have prevented us from overriding them.