|
CS 635: Advanced Object-Oriented Design & Programming |
|
---|
Spring Semester, 1998
Adapter
To Lecture Notes Index
© 1998, All Rights Reserved, SDSU & Roger Whitney
San Diego State University -- This page last updated 21-Apr-98
Contents of Doc 21, Adapter
CS 635 - Doc 21 Adapter
References | slide # 1 |
| |
Motivating Adapter | slide # 2 |
| |
Adapter | slide # 7 |
...Consequences | slide # 11 |
...Adapter Verses State | slide # 15 |
References
Design Patterns: Elements of Reusable Object-Oriented
Software, Gamma, Helm, Johnson, Vlissides, Addison
Wesley, 1995, pp 139-150
sdsu.net.CGI at:
http://www.eli.sdsu.edu/java-SDSU/sdsu.net.CGI.html
CGI Environment Variables at:
http://hoohoo.ncsa.uiuc.edu/cgi/env.html
Motivating Adapter
Java CGI & Servlets
Both Java CGI and servlets are used for server-side
processing of certain HTML requests, like processing
HTML forms
Servlets have greater functionality and are faster, but
require special Web servers or servers with special
extensions
To help write Java CGI programs there is class
sdsu.net.CGI
Adapters would be useful in moving code between servers
to avoid having to rewrite the code
There are various issues in writing such adapters
One issue is access to the CGI environment variables
There are about 20 common CGI environment variables
In servlets one has a HttpRequest class that has a getX()
method for each CGI environment variable
sdsu.net.CGI class returns a hash table with one entry per
CGI environment variable
Problem
Say we have a number of Java CGI programs we wish to
run as servlets
Do we have to rewrite all the CGI programs?
Solution
We have a class, HttpRequest, which has getX() methods
We have code that uses a class with get( "X" ) method
We can write a wrapper around HttpRequest to make it act
like a hash table
The Wrapper or Adapter
class CGIAdapter extends Hashtable
{
Hashtable CGIvariables = new Hashtable( 20);
public CGIAdapter( HttpRequest CGIEnvironment )
{
CGIvariables.put( "AUTH_TYPE" ,
CGIEnvironment.getAuthType());
CGIvariables.put( "REMOTE_USER" ,
CGIEnvironment.getRemoteUser());
etc.
}
public Object get(Object key)
{
return CGIvariables.get( key );
}
etc.
}
How does the CGI code get CGIAdapter?
In the CGI code one normally uses:
sdsu.net.CGI cgiGateWay = sdsu.net.CGI.getInstance();
Hashtable cgiVariables =
cgiGateWay.getCGIEnvironmentVariables();
We now have to make an subclass of sdsu.net.CGI whose
getCGIEnvironmentVariables returns CGIAdapter
To avoid more CGI details the complete code is not
shown
Going the other Direction
Adapting servlet code to normal CGI requires extracting
the CGI environment variables out of the hash table and
putting them into an object that implements the public
interface of the HttpRequest class
class HTTPAdapter extends HttpRequest
{
Hashtable CGIvariables;
public HTTPAdapter( Hashtable CGIEnvironment )
{
CGIvariables = CGIEnvironment;
}
public String getAuthType()
{
return (String) CGIvariables.get( "AUTH_TYPE" );
}
public String getRemoteUser()
{
return (String) CGIvariables.get( "REMOTE_USER" );
}
etc.
}
Adapter
The adapter pattern converts the interface of a class into
another interface.
Use the Adapter pattern when
- you want to use an existing class and its interface
does not match the one you need
- you want to create a reusable class that cooperates
with unrelated or unforeseen classes, that is classes
that don't necessarily have compatible interfaces
- you need to use several existing subclasses, but it's
impractical to adapt their interface by subclassing
everyone. An object adapter can adapt the interface of
its parent class
Adapter has two form:
- Class Adapter
- Object Adapter
Class Adapter
Object Adapter
Class Adapter Example
class OldSquarePeg {
public:
void squarePegOperation()
{ do something }
}
class RoundPeg {
public:
void virtual roundPegOperation = 0;
}
class PegAdapter: private OldSquarePeg,
public RoundPeg {
public:
void virtual roundPegOperation() {
add some corners;
squarePegOperation();
}
}
void clientMethod() {
RoundPeg* aPeg = new PegAdapter();
aPeg->roundPegOperation();
}
Object Adapter Example
class OldSquarePeg {
public:
void squarePegOperation() { do something }
}
class RoundPeg {
public:
void virtual roundPegOperation = 0;
}
class PegAdapter: public RoundPeg {
private:
OldSquarePeg* square;
public:
PegAdapter() { square = new OldSquarePeg; }
void virtual roundPegOperation() {
add some corners;
square->squarePegOperation();
}
}
Consequences
A Class adapter uses inheritance so
- only adapts a class and all its parents, not all its
subclasses
- lets Adapter override some of Adaptee's behavior
- does not introduce an additional pointer indirection
An object adapter uses object composition so
- lets a single Adapter work with many Adaptees
- makes it harder to override Adaptee behavior as the
Adapter may not know with Adaptee it is working with
Other issues:
- How much adapting does the Adapter do?
- Pluggable adapters
- Using two-way adapters
How Much Adapting does the Adapter do?
The adapter may have to work very little or a great deal to
adapt the Adaptee to the Target
The Adapter may just map one operation to another
class PegAdapter: public RoundPeg {
private:
OldSquarePeg* square;
public:
PegAdapter() { square = new OldSquarePeg;}
void roundPegOperation() {
square->squarePegOperation();
}
}
The Adapter may have to work hard if the Target operation
does not have a comparable operation in the Adaptee
Pluggable Adapters
In the CGI example we adapted a class with getX()
methods to a hash table interface
It is likely that we may adapt a class with getX() methods to
a hashtable in the future
It would be nice to write one class to do all such adapting
This class would be given a list of keys to getX methods
and an Adaptee object
HttpRequest CGIEnvironment = getHttpRequest();
PluggableHashAdapter sample =
new PluggableHashAdapter( CGIEnvironment );
sample.adapt( "AUTH_TYPE" , getAuthType );
sample.adapt( "REMOTE_USER" , getRemoteUser );
etc.
sample.get( "REMOTE_USER" );
Pluggable Adapters are used in interface components,
where we know in advance we will adapt the component to
other interfaces
Pluggable Adapters are common in Smalltalk, were it is
easier to map strings to method calls
Using two-way Adapter
In the SquarePeg-RoundPeg example the SquarePeg is
adapted to the RoundPeg
So a SquarePeg can be used where a RoundPeg is
needed, but not the other way around.
A two-way adapter would also allow a RoundPeg be used
in place of the SquarePeg
class OldSquarePeg {
public:
void virtual squarePegOperation() { blah }
}
class RoundPeg {
public:
void virtual roundPegOperation() { blah }
}
class PegAdapter: public OldSquarePeg, RoundPeg {
public:
void virtual roundPegOperation() {
add some corners;
squarePegOperation();
}
void virtual squarePegOperation() {
add some corners;
roundPegOperation();
}
}
Adapter Verses State
Both Adapter and State forward requests to an instance
object
That is both use object composition
What is the difference?
Adapter
State
visitors since 14-Apr-98