Advanced Object-Oriented Design & Programming
Spring Semester, 2005 Decorator, Proxy & Adapter |
||
---|---|---|
© 2005, All Rights Reserved, SDSU & Roger Whitney San Diego State University -- This page last updated 15-Feb-05 |
CS 635 Advanced Object-Oriented Design & Programming
Doc 6 Decorator, Proxy & Adapter
Copyright ©, All rights reserved. 2005 SDSU & Roger Whitney, 5500 Campanile Drive, San Diego, CA 92182-7700 USA. OpenContent ( http://www.opencontent.org/opl.shtml) license defines the copyright on this document.
CS 635 Spring 05 | Doc 6, Decorator, Proxy & Adapter Slide # 2 |
Design Patterns: Elements of Resuable Object-Oriented Software, Gamma, Helm, Johnson, Vlissides, Addison Wesley, 1995, pp. 175-185, 207-217, 139-150
The Design Patterns Smalltalk Companion, Alpert, Brown, Woolf, Addision-Wesley, 1998, pp. 161-178, 213-221, 105-120
CS 635 Spring 05 | Doc 6, Decorator, Proxy & Adapter Slide # 3 |
Changing the Skin of an Object
CS 635 Spring 05 | Doc 6, Decorator, Proxy & Adapter Slide # 4 |
A text view has the following features:
This gives 12 different options:
How to implement?
CS 635 Spring 05 | Doc 6, Decorator, Proxy & Adapter Slide # 5 |
class TextView { Border myBorder; ScrollBar verticalBar; ScrollBar horizontalBar; public void draw() { myBorder.draw(); verticalBar.draw(); horizontalBar.draw(); code to draw self } etc. }
But TextView knows about all the variations!
New type of variations require changing TextView
(and any other type of view we have)
CS 635 Spring 05 | Doc 6, Decorator, Proxy & Adapter Slide # 6 |
TextView has no borders or scrollbars!
Add borders and scrollbars on top of a TextView
CS 635 Spring 05 | Doc 6, Decorator, Proxy & Adapter Slide # 7 |
Use Decorator:
Commonly used in basic system frameworks
More flexible than static inheritance
Avoids feature laden classes high up in hierarchy
Lots of little objects
A decorator and its components are not identical
if ( aComponent instanceof TextView ) blah
CS 635 Spring 05 | Doc 6, Decorator, Proxy & Adapter Slide # 8 |
Keep Decorators lightweight
Don't put data members in VisualComponent
Have Decorator forward all component operations
Three ways to forward messages
CS 635 Spring 05 | Doc 6, Decorator, Proxy & Adapter Slide # 9 |
import java.io.*; import sdsu.io.*; class ReadingFileExample { public static void main( String args[] ) throws Exception { FileInputStream inputFile; BufferedInputStream bufferedFile; ASCIIInputStream cin; inputFile = new FileInputStream( "ReadingFileExample.java" ); bufferedFile = new BufferedInputStream( inputFile ); cin = new ASCIIInputStream( bufferedFile ); System.out.println( cin.readWord() ); for ( int k = 1 ; k < 4; k++ ) System.out.println( cin.readLine() ); } }
CS 635 Spring 05 Doc 6, Decorator, Proxy & Adapter Slide # 10
Insurance policies have payment caps for claims
Sometimes the people with the same policy will have different caps
A decorator can be used to provide different caps on the same policy object
Similarly for deductibles & copayments
CS 635 Spring 05 | Doc 6, Decorator, Proxy & Adapter Slide # 11 |
proxy n. pl prox-ies The agency for a person who acts as a substitute for another person, authority to act for another
The proxy has the same interface as the original object
Use common interface (or abstract class) for both the proxy and original object
Proxy contains a reference to original object, so proxy can forward requests to the original object
CS 635 Spring 05 | Doc 6, Decorator, Proxy & Adapter Slide # 12 |
CS 635 Spring 05 | Doc 6, Decorator, Proxy & Adapter Slide # 13 |
public class Proxy { Foo target; public float bar(int size ) { preprocess here float answer = target.bar( size); postProcess here return answer; } other methods as needed }
Preprocessing & post-processing depend on purpose of the proxy
CS 635 Spring 05 | Doc 6, Decorator, Proxy & Adapter Slide # 14 |
The actual object is on a remote machine (remote address space)
Hide real details of accessing the object
Used in CORBA, Java RMI
public class HelloClient { public static void main(String args[]) { try { String server = getHelloHostAddress( args); Hello proxy = (Hello) Naming.lookup( server ); String message = proxy.sayHello(); System.out.println( message ); } catch ( Exception error) { error.printStackTrace(); } } }
CS 635 Spring 05 Doc 6, Decorator, Proxy & Adapter Slide # 15
CS 635 Spring 05 | Doc 6, Decorator, Proxy & Adapter Slide # 16 |
public class Table { public Object elementAt( int row, int column ){ blah } public void setElementAt(Object element, int row, int column ) { blah} } public class RowLockTable { Table realTable; Integer[] locks; public RowLockTable( Table toLock) { realTable = toLock; locks = new String[ toLock.numberOfRows() ]; for (int row = 0; row< toLock.numberOfRows(); row++ ) locks[row] = new Integer(row); } public Object elementAt( int row, int column ) { synchronized ( locks[row] ) { return realTable.elementAt( row, column); } } public void setElementAt(Object element, int row, int column ){ synchronized ( locks[row] ) { return realTable.setElementAt(element, row, column); } } }
CS 635 Spring 05 Doc 6, Decorator, Proxy & Adapter Slide # 17
Delete original object when there are no references to it
Prevent accidental deletion of real subject
Collect usage statistics
Sample use is making C++ pointer safe
CS 635 Spring 05 | Doc 6, Decorator, Proxy & Adapter Slide # 18 |
When an object is sent a message
The object's class and the object's class’s superclasses are searched for the method
If the method is not found the object is sent the message:
This method in Object raises an exception
CS 635 Spring 05 | Doc 6, Decorator, Proxy & Adapter Slide # 19 |
One can use doesNotUnderstand: to implement a pluggable proxy
Object subclass: #Proxy instanceVariableNames: 'target ' classVariableNames: '' poolDictionaries: '' category: 'Whitney-Examples'
on: anObject ^super new target: anObject
doesNotUnderstand: aMessage ^target perform: aMessage selector withArguments: aMessage arguments
target: anObject target := anObject
CS 635 Spring 05 | Doc 6, Decorator, Proxy & Adapter Slide # 20 |
| wrapper | wrapper := Proxy on: Transcript. wrapper open. wrapper show: 'Hi mom'.
| wrapper | wrapper := Proxy on: 3. wrapper + 5.
| wrapper | wrapper := Proxy on: 'Hi '. wrapper , ' mom'.
CS 635 Spring 05 | Doc 6, Decorator, Proxy & Adapter Slide # 21 |
doesNotUnderstand:
CS 635 Spring 05 | Doc 6, Decorator, Proxy & Adapter Slide # 22 |
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
It would be useful in moving code between servers to avoid having to rewrite the code
CS 635 Spring 05 | Doc 6, Decorator, Proxy & Adapter Slide # 23 |
One issue is access to the CGI environment variables
There are about 20 common CGI environment variables
In servlets one has an 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
CS 635 Spring 05 | Doc 6, Decorator, Proxy & Adapter Slide # 24 |
We can write a wrapper around HttpRequest to make it act like a hash table
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. }
CS 635 Spring 05 | Doc 6, Decorator, Proxy & Adapter Slide # 25 |
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. }
CS 635 Spring 05 | Doc 6, Decorator, Proxy & Adapter Slide # 26 |
The adapter pattern converts the interface of a class into another interface.
Use the Adapter pattern when
Adapter has two forms:
CS 635 Spring 05 | Doc 6, Decorator, Proxy & Adapter Slide # 27 |
CS 635 Spring 05 | Doc 6, Decorator, Proxy & Adapter Slide # 28 |
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(); }
CS 635 Spring 05 | Doc 6, Decorator, Proxy & Adapter Slide # 29 |
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(); } }
CS 635 Spring 05 | Doc 6, Decorator, Proxy & Adapter Slide # 30 |
A Class adapter uses inheritance so
An object adapter uses object composition so
Other issues:
CS 635 Spring 05 | Doc 6, Decorator, Proxy & Adapter Slide # 31 |
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
CS 635 Spring 05 | Doc 6, Decorator, Proxy & Adapter Slide # 32 |
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 that we will adapt the component to other interfaces
Pluggable Adapters are common in Smalltalk, were it is easier to map strings to method calls
CS 635 Spring 05 | Doc 6, Decorator, Proxy & Adapter Slide # 33 |
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(); } }
Copyright ©, All rights reserved.
2005 SDSU & Roger Whitney, 5500 Campanile Drive, San Diego, CA 92182-7700 USA.
OpenContent license defines the copyright on this document.