Additional Design Pattern Examples • Creational – Factory method – Abstract factory • Structural – Decorator – Adapter • Behavioral – Observer
Design Patterns--Factory Method • Intent--Permit a class to be reuseable with arbitrary data types. Specifically, allow the class to be independent of the classes it instantiates – Define an interface for object creation. – Let subclasses decide which class to instantiate. • Motivation – Useful for development of frameworks
1 Factory Method--Continued
• Consider a document-processing framework – High-level support for creating, opening, saving documents – Consistent method calls for these commands, regardless of document type (word-processor, spreadsheet, etc.) – Logic to implement these commands delegated to specific types of document objects. – May be some operations common to all document types.
Factory Method--Continued Document Processing Example-General Framework:
Document Application getTitle( ) * Edits 1 newDocument( ) newDocument( ) openDocument( ) openDocument( ) ......
MyDocument Problem: How can an Application object newDocument( ) create instances of specific document classes openDocument( ) without being application-specific itself. ...
2 Factory Method--Continued Use of a document creation “factory”: Document Application getTitle( ) * Edits 1 newDocument( ) newDocument( ) openDocument( ) openDocument( ) ...... 1 requestor * Requests-creation creator 1 <
DocumentFactory creates 1 createDocument(type:String):Document
Product Uses CreationRequestor * 1 Operation1( ) newDocument( ) Operation2( ) ... … 1 requestor * Requests-creation creator 1 ConcreteProduct <
Creates Factory 1 createProduct(discriminator):Product
3 Factory Example--Encrypted Sockets Socket Encryption * Encrypts-and-decrypts-bytes encryptor/decryptor 1 encrypedOutputStream( ) byte source decrypedInputStream( ) EncryptedSocket <
Creates 1 EncryptionFactory 1 createEncryption(key):Encryption
Factory Example--Java Implementation import java.io.InputStream; import java.io.IOException; import java.io.OutputStream; import java.net.Socket; import java.security.Key; import java.security.NoSuchAlgorithmException; /** * This class extends socket so that the stream of bytes that goes over the net is encrypted. */ public class EncryptedSocket extends Socket { private static Encryption crypt; private Key key; /** * Constructor * @param key The key to use for encryption and decryption. This object will determine the * encryption technique to use by calling the key object's getAlgorithm() method. * @param factory The Factory object to use to create Encryption * objects. * @exception NoSuchAlgorithmException if the key specifies an encryption technique that * is not available. */
4 Java Implementation--Continued public EncryptedSocket(Key key, EncryptionFactoryIF factory) throws NoSuchAlgorithmException { this.key = key; crypt = factory.createEncryption(key); } // Constructor(Key, EncryptionFactoryIF) /** * Returns an input stream for this socket that decrypts the inbound stream of bytes. * * @return an input stream for reading decrypted bytes from this socket. * @exception IOException if an I/O error occurs when creating the input stream. */ public InputStream getInputStream() throws IOException { return crypt.decryptInputStream(super.getInputStream()); } // getInputStream() /** * Returns an output stream for this socket that encrypts theoutbound stream of bytes. * * @return an output stream for reading decrypted bytes from this socket. * @exception IOException if an I/O error occurs when creating the output stream. */ public OutputStream getOutputStream() throws IOException { return crypt.encryptOutputStream(super.getOutputStream()); } // getOutputStream() } // class EncryptedSocket
Java Implementation--Continued
import java.security.Key; import java.security.NoSuchAlgorithmException;
/** * This interface must be implemented by all factory classes used to create instances of * subclasses of Encryption. */ public interface EncryptionFactoryIF { /** * This method returns an instance of the appropriate subclass of Encryption as determined * from information provided by the given Key object. * @param key The key that will be used to perform the encryption. */ public Encryption createEncryption(Key key) throws NoSuchAlgorithmException; } // interface EncryptionFactoryIF
5 Java Implementation--Continued
/** * This class creates instances of appropriate subclasses of Encryption. * The appropriate subclass is determined by calling the Key object's */ public class EncryptionFactory implements EncryptionFactoryIF { /** * This method returns an instnace of the appropriate subclass of Encryption as determined * from information provided by the given Key object's getAlgorithm method. * @param key The key that will be used to perform the encryption. */ public Encryption createEncryption(Key key) throws NoSuchAlgorithmException{ String algorithm = key.getAlgorithm(); if ("DES".equals(algorithm)) return new DESEncryption(key); if ("RSA".equals(algorithm)) return new RSAEncryption(key); throw new NoSuchAlgorithmException(algorithm); } // createEncryption(Key) } // class EncryptionFactory
Java Implementation--Continued
/** /** * Abstract class to encrypt/decrypt * This method returns an OutputStream that * streams of bytes. * encrypts the bytes written to it and writes */ * the encrypted bytes to the given OutputStream. abstract public class Encryption { * @param out The OutputStream that the private Key key; * OutputStream returned by this method /** * will write encrypted bytes to. * Constructor */ * @param key The key to use to perform abstract OutputStream encryptOutputStream * the encryption. (OutputStream out); */ /** public Encryption(Key key) { * This method returns an InputStream that this.key = key; * decrypts the stream of bytes that it reads from } // Constructor(Key) * the given InputStream. * @param in The InputStream that the /** * InputStream returned by this * Return the key this object used for * method will read bytes from. * encryption and decryption. */ */ abstract InputStream decryptInputStream protected Key getKey() { (InputStream in); return key; } // class Encrypt } // getKey()
6 A More Streamlined Version of Factory Method
uses Creator … Product FactoryMethod( ) product=FactoryMethod( ) AnOperation( ) ...
creates ConcreteCreator ConcreteProduct FactoryMethod( ) return new ConcreteProduct
The Abstract Factory Pattern • Intent: – Provide an interface for creating families of related or dependent objects without specifying their concrete classes • Also Known as: – kit – toolkit
7 Abstract Factory Pattern-- Motivation
uses WidgetFactory Client CreateScrollBar( ) Window CreateWindow( ) uses
PMWindow MotifWindow
MotifWidgetFactory creates PMWidgetFactory uses CreateScrollBar( ) CreateScrollBar( ) ScrollBar CreateWindow( ) CreateWindow( )
creates PMScrollBar MotifScrollBar creates creates
Abstract Factory Pattern Structure
uses AbstractFactory Client CreateProductA( ) AbstractProductA CreateProductB( ) uses
ProductA2 ProductA1 creates ConcreteFactory1 ConcreteFactory2 uses CreateProductA( ) CreateProductA( ) AbstractProductB CreateProductB( ) CreateProductB( )
creates ProductB2 ProductB1 creates creates
8 Structural Patterns--Decorator • Intent – Extend the functionality of an object without subclassing. – Allow object functionality to be extended and restricted dynamically. • Also known as – wrapper pattern
Decorator Pattern Example • Consider a TextView object – displays text in a window – no scroll bars – no border • Want to be able to extend text view to permit scrollbars and borders • Don’t want to use inheritance to extend functionality of TextView. • Solution: Use composition of Textview object with “decorator” objects
9 Decorator Example--Continued
Visual Component 1 Draw( ) ... component
TextView Decorator 1 Draw( ) Draw( ) component.Draw( )
ScrollDecorator BorderDecorator
ScrollPosition BorderWidth super.Draw( ) Draw( ) Draw( ) DrawBorder( ) ScrollTo( ) DrawBorder( )
Decorator Pattern--General Structure
AbstractComponent 1 Operation( ) ... component
ConcreteComponent AbstractDecorator 1 Operation( ) Operation( ) component.Operation( )
ConcreteDecoratorA ConcreteDecoratorB
AddedState AddedState super.Operation( ) Operation( ) Operation( ) AddedBehavior( ) AddedBehavior( ) AddedBehavior( )
10 Decorator Pattern--Java Code Example abstract class VisualComponent( ) { public void Draw( ); public void Resize( ); … } // class VisualComponent
abstract class Decorator extends VisualComponent { private VisualComponent component; public Decorator (VisualComponent comp) { this.component = comp; } // constructor public Draw( ) { component.Draw( ); } // Draw public Resize( ) { component.resize( ); }// Resize ... }// class Decorator
Decorator Example--Continued
class BorderDecorator extends Decorator { private int width;
public BorderDecorator(VisualComponent comp, int BorderWidth) { super(comp); // call constructor of parent class this.width = BorderWidth; } // Constructor
private void DrawBorder { … // code to implement Draw Border method } // DrawBorder
public Draw( ) { super.Draw( ); DrawBorder(width); } // Draw
11 Decorator Pattern Code--Continued class ScrollDecorator extends Decorator { private int position = 0;
public ScrollDecorator(VisualComponent comp) { super(comp); // call constructor of parent class } // Constructor
private void ScrollTo(int newposition) { … // code to implement ScrollTo method } // ScrollTo
private void DrawScroll( ) { … // code to implement DrawScroll method } // DrawScroll
public Draw( ) { super.Draw( ); DrawScroll; } // Draw
Decorator Pattern Code--Continued
Now we can create a text object with scroll bar and border as follows:
TextView text = new TextView(); ScrollDecorator stext = new ScrollDecorator(text); VisualComponent bstext = new BorderDecorator(stext);
12 Decorator Pattern Example--Object Composition
bstext stext
delegates text Draw Draw delegates Draw DrawBorder DrawScroll
ScrollTo(x) (Note that client would require knowledge of the stext object
Structural Pattern--Adapter
• Intent: Translates between an interface expected by clients and the interface of otherwise incompatible objects. • Motivation: – allows classes to work together that otherwise couldn’t – permits you to use an existing class that doesn’t have the interface that you need.
13 Adapter Pattern--General Structure Class Adapter: <
Adapter Request( ) SpecificRequest( ) Object Adapter: <
adaptee Adapter Request( ) adaptee.SpecificRequest( )
Behavioral Patterns--Observer • Intent--Allow multiple dependent objects to be notified when the state of an object changes. • Also known as: publisher-subscriber
14 Observer Pattern--General Structure
Subject observed by Observer Attach(observer) 1 * Update( ) Detach(observer) Notify( ) for all o in observers { o.Update( ) }
ConcreteSubject subject ConcreteObserver subjectState observerState GetState( ) return SubjectState Update( ) SetState( )
observerState = subject.GetState( )
Observer--Use of a Multicaster
Registers <
Notifies
Observable Observer 1 1 Registers-observers Notifies 1 1 Multicaster addObserver(:ObserverIF) removeObserver(:ObserverIF)
15 Observer and Adapter Pattern Example--The Java Event Model • Indirect coupling between an object that fields an event and other objects interested in the event (listeners) • based on the observer pattern • An observed component needs no knowledge about the number and structure of listeners • Such loose coupling creates a plug-n-play architecture capability
Java Events • Public methods and events are used for communication with the outside world • Strong typing is enforced through interface classes which must be implemented by both the observed (alternatively the multicaster) and observer • Examples from the Advanced Windowing Tool Kit (AWT) – Listener interfaces and adapters
16 More about Java Events
• Events are a class hierarchy • Events are not usually changed as they are passed between objects • Events have public attributes and operations used for its interpretation by a listener • Synchronization can cause deadlocks if the observed object holds locks
java.awt.event Events
ActionEvent ContainerEvent
AdjustmentEvent FocusEvent
KeyEvent
AWTEvent Abstract ComponentEvent Java.awt-events InputEvent
MouseEvent
itemEvent PaintEvent
TextEvent WindowEvent
17 java.awt.event Listener Interfaces
Interface ActionListener
Interface AdjustmentListener
Interface abstract CoomponentListener ComponentAdapter
Interface abstract ContainerListener ContainerAdapter Interface EventListener abstract java.util FocusListener FocusAdapter
Interface ItemListener
Interface abstract KeyListener KeyAdapter
Interface abstract MouseListener MouseListenerAdapter Interface MouseMotionListener abstract Interface MouseMotionAdapter TextListener
Interface abstract WindowListener WindowAdapter
Graphical User Interface Example
This string is an attribute of textField
java.awt.textField java.awt.button
18 Sends Event to Every Added Listener
AWTEventMulticaster Interface ActionListener ActionPerformed(); ActionPerformed(); Implements Add(); Remove();
Add Remove multicaster Implements ActionPerformed ->Add(l);
ZapTextField Button AddActionListener(ActionListoner l); AddActionListener ActionPerformed(); performActionEvent(ACtionEvent e);
Multicaster looks like an ActionListener Object giving: actionListener.ActionPerformed(e);
Object
TextField
Component
Attribute: String text TextComponent int columns char EchoChar
Methods: Methods: int getCaretPosition(); synchronized void addActionListener(ActionListener l); synchronized boolean echoCharIsSet(); getSelectedText(); int getColumns(); sychronized in char getEchoChar(); getSelectionEnd(); Dimension getMinimumSize(); setText(String t). synchronized void
.... removeActionListener(ActionListener l); void setColumns(int Columns); void setEchoChar(char C); protected void processActionEvent(ActionEvent e); protected void processEvent(AWTEvent e);
19 Component
Methods: synchronized void addMouseListener(MouseListener l); protected void processMouseEvent(MouseEvent e); protected void processMouseMotionEvent(MouseMotionEvent e); ... public boolean IsEnabled();
Button
Attributes: string label; Methods: String getLabel(); synchronized void setLabel(String label); synchronized void addActionListener(ActionListener l); ...
Button Attaches Observer
Adds the specified action listener to receive action events from this button. Action events occur when a user presses or releases the mouse over this button. public synchronized void addActionListener(ActionListener l) { actionListener = AWTEventMulticaster.add(actionListener, l); }
20 Button Sends Action Event to all Observers
protected void processActionEvent(ActionEvent e) { if (actionListener != null) { actionListener.actionPerformed(e); } }
Extended Text Field as an Observer
public class ZapTextField extends TextField implements ActionListener { public ZapTextField() {attachButton();} protected void attachButton() { button1.addActionListener(this); } public void actionPerformed(ActionEvent e) { this.setText(”~~~~~~~~~"); } }
21 Adapters in Java API
• Adapters are implemented as classes with stubbed methods • Classes using the adapter extend only those stubbed methods that they need. • Without the use of an adapter, a class that implements and interface would have to implement all of the methods in that interface, even if it isn’t interested in all of them.
Mouse Adapter
Interface MouseListener
public abstract void mouseclicked(MouseEvent e); public abstract void mouseEntered(MouseEvent e); public abstract void mouseExited(MouseEvent e); public abstract void mousePressed(MouseEvent e); public abstract void mouseReleased(MouseEvent e);
Implements
MouseAdapter
public void mouseclicked(MouseEvent e) {} public void mouseEntered(MouseEvent e) {} public void mouseExited(MouseEvent e) {} public void mousePressed(MouseEvent e) {} public void mouseReleased(MouseEvent e) {}
Extends
Button public void mouseclicked(MouseEvent e) { ... }
22 Use of Adapters in the Java API
Event Handling using an anonymous inner class:
Button pushMe = new Button(“Push Me”) pushMe.addActionListener(new ActionListener( ) { public void actionPerformed(actionEvent evt) { doSomethingFantastic(ActionEvent) } // actionPerformed(ActionEvent) } ); add (pushMe); . . .
Note: The Java API contains a number of abstract adapter classes-- e.g. WindowAdapter in AWT (InternalFrameAdapter in Swing). Look at the Java API Specification and determine the purpose of these adapters.
23