Upload
liesel
View
36
Download
1
Embed Size (px)
DESCRIPTION
Creational Design Patterns. Factory Method Abstract Factory Builder Prototype Singleton Object Pool. CDP - Factory Method. Synopsis: Need for a class for reuse with arbitrary data types. - PowerPoint PPT Presentation
Citation preview
Creational Design Patterns
Factory Method
Abstract Factory
Builder
Prototype
Singleton
Object Pool
CDP - Factory Method
Synopsis:
Need for a class for reuse with arbitrary data types.
Reusable class remains independent of the classes it instantiates by delegating the choice of which class to instantiate to another object and referring to the newly created object through a common interface.
Context:
Creates a framework to support instantiations of various data types.
CDP - Factory Method
Forces:
Provide services (methods) in a way transparent to classes using those services.
Solution:
Proxy object and the service providing object must either be instances of a common super class or implement a common interface.
Consequences:
Could introduce new failure points.
CDP - Factory Method - ExampleYou have an application such as MS Office.
You want to perform some common functions with all the files.
Example of common functions might be open file, save file, etc.
The only difference is that the functions are done on different file types such as word doc files, excel xls files and PowerPoint ppt files.
You could write several independent functions for each of the different types but the code would be very similar with only the data type as a difference.
The factory method allows you to build a framework to perform the common functions with only a few classes that reused for each type.
Manage Files
file commands
ManageDoc Files
doc file commands
ManageXls Files
xls file commands
ManagePpt Files
ppt file commands
Make one Function
CDP - Factory Method - Example
CDP - Factory Method - Example
Document Applicationedits 1
*
MyDocument May be doc, xls, or ppt.
CDP - Factory Method - Example
Document Applicationedits 1
*
MyDocument
DocumentFactoryIF
Requests creation
DocumentFactory
creates
Write to Socket
stream
CDP - Factory Method - Example
Socket
But you also wish to have strings in which you encrypt the data.And you write an encrypted DataStream and read back an encrypted Data Stream decrypt it.
string
Suppose you have a process which reads and writes a DataStream to a socket.
Read from Socket
stream Socketstring
Write to Encrypted
Socket
encrypted stream
CDP - Factory Method - Example
EncryptedSocketencrypted string
Encrypt Data
string Write to Encrypted
Socket
encrypted stream
EncryptedSocketencrypted string
Read from Socket
encryptedstream
Socketencrypted stringDecrypt
Data
decrypted string
But now you realize that there are several different encryption algorithms and codes you wish to use.
CDP - Factory Method - Example
Encrypt Data
string Write to Encrypted
Socket
encrypted stream
EncryptedSocketencrypted String #1
algorithm # 1
The process to encrypt differs in using many different different algorithms (function/method) and type of string output must be written for each type.
Encrypt Data
string Write to Encrypted
Socket
encrypted stream
EncryptedSocketencrypted String #2
algorithm # 2
Encrypt Data
string Write to Encrypted
Socket
encrypted stream
EncryptedSocketencrypted String #n
algorithm # n
CDP - Factory Method - Example
Encrypt Data
string Write to Encrypted
Socket
encrypted stream
EncryptedSocketencrypted String
algorithm # 1
algorithm # 2
algorithm # n
The factory pattern allows you to have a framework that will handle any type of algorithm and encrypted data.
concrete product
CDP - Factory Method - Example
Encryption
Socket
encrypt, decrypt 1
*
DESEncryption
EncryptedSocket
Transcription
EncryptionFactory
EncryptionFactoryIF
creates
requestCreation
creates11
*
*
*
1
Concrete Product
Product
Factory
Socket
EncryptedSocket
Interface
Creation Requester
1
2
3
4
5
6
CDP - Factory Method - Example
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 to encrypt the stream of bytes over the net.
public class EncryptedSocket extends Socket {
private static Encryption crypt;
private Key key;
Encryption
Socket
encrypt, decrypt 1*
DESEncryption
EncryptedSocket
Transcription
EncryptionFactory
EncryptionFactoryIF
creates
requestCreation
creates11
*
*
*
1
CDP - Factory Method - Example
// Constructor
// @param Key for encryption and decryption.
// Determines encryption technique by calling key object's getAlgorithm() method.
// @param Factory object to use to create Encryption objects.
// @exception NoSuchAlgorithmException if key specifies technique not available.
public EncryptedSocket(Key key, EncryptionFactoryIF factory)
throws NoSuchAlgorithmException {
this.key = key;
crypt = factory.createEncryption(key);
} // Constructor(Key, EncryptionFactoryIF)
Encryption
Socket
encrypt, decrypt 1*
DESEncryption
EncryptedSocket
Transcription
EncryptionFactory
EncryptionFactoryIF
creates
requestCreation
creates11
*
*
*
1
CDP - Factory Method - Example
// Returns an input stream that decrypts the inbound stream of bytes.
// @return an input stream for reading decrypted bytes
// @ 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 that encrypts the outbound stream of bytes.
// @return an output stream for reading decrypted bytes
// @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
CDP - Factory Method - Example
import java.io.InputStream;
import java.io.OutputStream;
import java.security.Key;
// Abstract class to encrypt/decrypt streams of bytes.
abstract public class Encryption {
private Key key;
// * Constructor * @param key The key to use to perform the encryption.
public Encryption(Key key) {
this.key = key;
} // Constructor(Key)
// * Return the key this object used for encryption and decryption.
protected Key getKey() {
return key;
} // getKey()
Encryption
Socket
encrypt, decrypt 1*
DESEncryption
EncryptedSocket
Transcription
EncryptionFactory
EncryptionFactoryIF
creates
requestCreation
creates11
*
*
*
1
CDP - Factory Method - Example
// This method returns an OutputStream.
// It encrypts bytes written to it.
// And it writes the encrypted bytes to the given OutputStream.
// @param out OutputStream that OutputStream returned writes encrypted bytes.
abstract OutputStream encryptOutputStream(OutputStream out);
// This method returns an InputStream.
// It decrypts the stream of bytes read from the given InputStream.// @param in InputStream that InputStream returned reads bytes.
abstract InputStream decryptInputStream(InputStream in);
} // class Encrypt
CDP - Factory Method - Example
import java.security.Key;
import java.security.NoSuchAlgorithmException;
// This interface must be implemented by all factory classes
// that are used to create instances of subclasses of Encryption.
public interface EncryptionFactoryIF { // Returns an instance of appropriate subclass of Encryption.
// The instance is determined from information provided by the given Key object.
// @param key will be used to perform the encryption.
public Encryption createEncryption(Key key) throws NoSuchAlgorithmException;
} // interface EncryptionFactoryIF
Encryption
Socket
encrypt, decrypt 1*
DESEncryption
EncryptedSocket
Transcription
EncryptionFactory
EncryptionFactoryIF
creates
requestCreation
creates11
*
*
*
1
CDP - Factory Method - Example
import java.security.Key;
import java.security.NoSuchAlgorithmException;
// This class creates instances of appropriate subclasses of Encryption.
//The appropriate subclass is determined by calling the Key object's
public class EncryptionFactory {
Encryption
Socket
encrypt, decrypt 1*
DESEncryption
EncryptedSocket
Transcription
EncryptionFactory
EncryptionFactoryIF
creates
requestCreation
creates11
*
*
*
1
CDP - Factory Method - Example
// Returns an instanace of the appropriate subclass of Encryption.
// It is determined 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
Encryption
Socket
encrypt, decrypt 1*
DESEncryption
EncryptedSocket
Transcription
EncryptionFactory
EncryptionFactoryIF
creates
requestCreation
creates11
*
*
*
1
CDP - Factory Method - Example
import java.io.InputStream;
import java.io.FilterInputStream;
import java.io.FilterOutputStream;
import java.io.OutputStream;
import java.security.Key;
// class to DES encrypt/decrypt streams of bytes.
public class DESEncryption extends Encryption {
/**
* Constructor
* @param key The key to use to perform the encryption.
*/
public DESEncryption(Key key) {super(key); } // Constructor(Key)
Encryption
Socket
encrypt, decrypt 1*
DESEncryption
EncryptedSocket
Transcription
EncryptionFactory
EncryptionFactoryIF
creates
requestCreation
creates11
*
*
*
1
CDP - Factory Method - Example
// Returns an OutputStream that encrypts the bytes written to it/
// And writes the encrypted bytes to the given OutputStream.
// @param out OutputStream that OutputStream returned by this method writes encrypted bytes.
OutputStream encryptOutputStream(OutputStream out) {
return new DESEncrytpedOutputStream(out);
} // encryptOutputStream(OutputStream)
Encryption
Socket
encrypt, decrypt 1*
DESEncryption
EncryptedSocket
Transcription
EncryptionFactory
EncryptionFactoryIF
creates
requestCreation
creates11
*
*
*
1
CDP - Factory Method - Example
/**
* This method returns an InputStream that decrypts the stream of
* bytes that it reads from the given InputStream. * @param in The InputStream that the InputStream returned by this
* method will read bytes from.
*/
InputStream decryptInputStream(InputStream in) {
return new DESEncrytpedInputStream(in);
} // decryptInputStream(InputStream)
Encryption
Socket
encrypt, decrypt 1*
DESEncryption
EncryptedSocket
Transcription
EncryptionFactory
EncryptionFactoryIF
creates
requestCreation
creates11
*
*
*
1
CDP - Abstract Factory Method
Synopsis:
Need for a class for reuse with abstract classes.
Reusable class remains independent of the classes it instanciates by delegating the choice of which class to instanciate to another object and referring to the newly created object through a common interface.
Context:
Creates a framework to support instanciations of various abstract classes.
Forces:
Provide services (methods) in a way transparent to classes using those services.
Solution:
Proxy object and the service providing object must either be instances of a common super class or implement a common interface.
Consequences:
Could introduce new failure points.
CDP - Abstract Factory Method
CDP - Abstract Factory Method
Displaywindows textfield
Suppose you have a textfield or any other GUI component and you wish to display it on a particular platform.
CDP - Abstract Factory Method
Displaywindows textfield
Suppose you wish to display those GUI componentson various platforms.
MacOS textfield
Linix textfield
Certainly each platform expects to see different Java byte code.
CDP - Abstract Factory Method
Architecture Toolkit
uses
EmberToolkit
Client
EnginolaToolkit
requestCreation
creates1*
*
1
CPUuses
EmberCPU
EnginolaCPU
creates
creates
MMU
EnginolaMMU EmberMMU
uses
Concrete FactoryConcrete Product
Abstract Factory
Request services
CDP - Abstract Factory Method
// Sample client class shows how a client class can create concrete widget objects using an abstract factory
public class Client {
public void doIt () {
ArchitectureToolkit af;
af = ArchitectureToolkit.getFactory(ArchitectureToolkit.EMBER);
CPU cpu = af.createCPU();
//...
} //doIt
} // class Client
CDP - Abstract Factory Method
// Abstract factory class for creating objects for remote tests on computer components.
public abstract class ArchitectureToolkit {
private static final EmberToolkit emberToolkit = new EmberToolkit();
private static EnginolaToolkit enginolaToolkit = new EnginolaToolkit();
//...
// Symbolic names to identify types of computers
public final static int ENGINOLA = 900;
public final static int EMBER = 901;
// ...
CDP - Abstract Factory Method
// Returns a concrete factory object as an instance of the concrete factory class.
// It is appropriate for the given computer architecture.
// @param architecture - value indicating architecture that concrete factory returned for.
static final ArchitectureToolkit getFactory(int architecture) {
switch (architecture) {
case ENGINOLA: return enginolaToolkit;
case EMBER: return emberToolkit;
// ...
} // switch
String errMsg = Integer.toString(architecture);
throw new IllegalArgumentException(errMsg);
} // getFactory()
CDP - Abstract Factory Method
// Method to create objects for remote testing CPUs.
public abstract CPU createCPU() ;
// Method to create objects for remote testing MMUs.
public abstract MMU createMMU() ;
//...
} // ArchitectureToolkit
CDP - Abstract Factory Method
// This is a concrete factory class for creating objects used to perform remote tests.
// These tests are on core components of ember architecture computers.
class EmberToolkit extends ArchitectureToolkit {
// Method to create objects for remote testing ember CPUs.
public CPU createCPU() { return new EmberCPU(); } // createCPU()
// Method to create objects for remote testing ember MMUs.
public MMU createMMU() { return new EmberMMU(); } // createMMU()
//...
} // class EmberToolkit
CDP - Abstract Factory Method
// This is a concrete factory class for creating objects used to perform remote tests.
// These tests are on core components of enginola architecture computers.
class EnginolaToolkit extends ArchitectureToolkit {
// Method to create objects for remote testing enginola CPUs.
public CPU createCPU() { return new EnginolaCPU(); } // createCPU()
// Method to create objects for remote testing enginola MMUs.
public MMU createMMU() { return new EnginolaMMU(); } // createMMU()
//...
} // class EnginolaToolkit
CDP - Abstract Factory Method
// This is an abstract class for objects that perform remote tests on CPUs.
public abstract class CPU extends ComponentTester {
//...
} // class CPU
// This is an abstract class for objects that perform remote tests on CPUs.
public abstract class CPU extends ComponentTester {
//...
} // class CPU
CDP - Abstract Factory Method
// Class for objects that perform remote tests on Ember architecture CPUs.
class EmberCPU extends CPU {
//...
} // class EmberCPU
// Class for objects that perform remote tests on Enginola architecture CPUs.
class EnginolaCPU extends CPU {
//...
} // class EnginolaCPU
CDP - Abstract Factory Method
// This is an abstract class for objects that perform remote tests on MMUs.
public abstract class MMU extends ComponentTester {
//...
} // class MMU
_________________________________________________________________________
// Class for objects that perform remote tests on Enginola architecture MMUs.
class EnginolaMMU extends MMU {
//...
} // class EnginolaMMU
_________________________________________________________________________
// Class for objects that perform remote tests on Ember architecture MMUs.
public class EmberMMU extends MMU {
//...
} // class EmbeMMU
CDP - Builder
Synopsis: Need to build an instance of an object depending on the type of instance needed.
Context: Allows a client object to construct a complex object by specifying only its type and content.
Forces: Program required to produce multiple external representations of the same data.
Solution:
Abstract Builder builds and returns the data representation needed.
Concrete builder, subclass of abstract builder, used to build a specific kind of data representation.
Consequences:
Provides finer control over construction that other patterns.
CDP - Builder
Forward E-mail
format 1
Suppose you have an e-mail gateway program. The program receives a message in MIME format and forwards them in a different format for a different kind of e-mail system.
CDP - Builder
MIME mail
Destination 1format 2
Destination 1format n
Destination 1
You have a procedure (set of methods) for each format builder routine. The methods are similar but you need multiple procedures.The builder pattern allows you to use one method for all formats.
BuildFormat
format whatever
You want a class to build the format needed depending on the Destination using a builder class.
CDP - Builder
MIME mail
Destination 1
Destination 1
Destination 1
ForwardedE-Mail
CDP - Builder
MessageManagermanages
PRoFMsg
MIMEMsg
MAPIMsg
creates
requestCreation
creates1*
*
MIMEParser
MessageBuilder
MAPIBuilder PROFSBuilder
OutboundMessageIF
sendsis parsed by
directs
Product
Director
ProductIF
1: receive(MIME)
2: parse(MIME)
3: build
4: send
CDP - Builder (collaboration diagram)
MessageManager MIMEParser
MessageBuilder Builder:MAPIBuilder
outMsg:OutboundMessageIF
1.2: send( )
1.1: outMsg:=parse(msg:MIMEMsg)1: receive (msg:MIMEMsg)
1.1.2: to(:String)1.1.3:from(:String)1.1.4:plainText(:String)1.1.5:jpegImage(:Image)1.1.6:outMsg :=getOutboundMsg( )
1.1.1: builder:=getInstance(to:String)
1: receive(MIME) 2: parse(MIME)
3: build
4: send
CDP - Builderimport java.awt.Image;
// This is an abstract builder class for building e-mail messages
abstract class MessageBuilder { // Return an object of the subclass for the e-mail message format implied by the destination address.
//@param dest The e-mail address the message is to be sent to
static MessageBuilder getInstance(String dest) {
MessageBuilder builder = null;
//...
return builder;
} // getInstance(String)
MessageManager MIMEParser
MessageBuilder Builder:MAPIBuilder
outMsg:OutboundMessageIF
1.2: send( )
1.1: outMsg:=parse(msg:MIMEMsg)1: receive (msg:MIMEMsg)
1.1.2: to(:String)1.1.3:from(:String)1.1.4:plainText(:String)1.1.5:jpegImage(:Image)1.1.6:outMsg :=getOutboundMsg( )
1.1.1: builder:=getInstance(to:String)
1: receive(MIME) 2: parse(MIME)
3: build
4: send
CDP - Builder // pass the value of the "to" header field to this method.
abstract void to(String value);
// pass the value of the "from" header field to this method.
abstract void from(String value);
//...
// pass the value of the "organization" header field to this method.
void organization(String value) { }
// pass the content of a plain text body part to this method.
abstract void plainText(String content);
// pass the content of a jpeg image body part to this method.
abstract void jpegImage(Image content) ;
// complete and return the outbound e-mail message.
abstract OutboundMessageIF getOutboundMsg() ;
} // class MessageBuilder
CDP - Builder // Class used to represent raw MIME e-mail messages.
// If program expanded to receive messages in formats other than MIME,
// then this will probably become an abstract class with a subclass for each type of e-mail.
public class MIMEMessage {
private byte[] rawMessage;
// Constructor @param msg A byte array containing a raw unprocessed e-mail message.
public MIMEMessage(byte[] msg) { rawMessage = msg; } // constructor(byte[])
// Return the raw bytes of an unprocessed e-mail message.
byte[] getMessage() { return rawMessage; } // getMessage()
} // class MIMEMessage
CDP - Builder
import java.awt.Image;
// This is a class to parse MIME e-mail messages.
class MIMEParser {
private MIMEMessage msg; // The message being parsed
private MessageBuilder builder; // The builder object
//...
MessageManager MIMEParser
MessageBuilder Builder:MAPIBuilder
outMsg:OutboundMessageIF
1.2: send( )
1.1: outMsg:=parse(msg:MIMEMsg)1: receive (msg:MIMEMsg)
1.1.2: to(:String)1.1.3:from(:String)1.1.4:plainText(:String)1.1.5:jpegImage(:Image)1.1.6:outMsg :=getOutboundMsg( )
1.1.1: builder:=getInstance(to:String)
1: receive(MIME) 2: parse(MIME)
3: build
4: send
CDP - Builder
// parse MIME message, call builder methods for message's header fields and body parts.
OutboundMessageIF parse(MIMEMessage msg) {
this.msg = msg;
builder = MessageBuilder.getInstance(getDestination());
MessagePart hdr = nextHeader();
while (hdr != null) {
if (hdr.getName().equalsIgnoreCase("to"))
builder.to((String)hdr.getValue());
else if (hdr.getName().equalsIgnoreCase("from"))
builder.from((String)hdr.getValue());
//...
hdr = nextHeader();
} // while hdr
CDP - Builder MessagePart bdy = nextBodyPart();
while (bdy != null) {
if (bdy.getName().equals("text/plain")) builder.plainText((String)bdy.getValue()); //...
else if (bdy.getName().equals("image/jpeg")) builder.jpegImage((Image)bdy.getValue());
//...
bdy = nextHeader();
} // while body
return builder.getOutboundMsg();
} // parse(MIMEMessage)
private MessagePart nextHeader() {
MessagePart mp = null;
//...
return mp;
} // nextHeader()
CDP - Builder
private MessagePart nextBodyPart() {
MessagePart mp = null;
//...
return mp;
} // nextBodyPart()
// return the destination e-mail address for the message
private String getDestination() {
String dest = null;
//...
return dest;
} // getDestination()
CDP - Builder private class MessagePart {
private String name;
private Object value;
// Consructor
MessagePart(String name, Object value) {
this.name = name;
this.value = value;
} // Consructor(String, String)
String getName() { return name; }
Object getValue() { return value; }
} // class MessagePart
} // class MIMEParser
CDP - Builder
// All classes that are used to represent outbound messages will implement this interface.
public interface OutboundMessageIF {
public void send() ;
} // interface OutboundMessageIF
MessageManager MIMEParser
MessageBuilder Builder:MAPIBuilder
outMsg:OutboundMessageIF
1.2: send( )
1.1: outMsg:=parse(msg:MIMEMsg)1: receive (msg:MIMEMsg)
1.1.2: to(:String)1.1.3:from(:String)1.1.4:plainText(:String)1.1.5:jpegImage(:Image)1.1.6:outMsg :=getOutboundMsg( )
1.1.1: builder:=getInstance(to:String)
1: receive(MIME) 2: parse(MIME)
3: build
4: send
CDP - Prototype
Synopsis:
Allows creation of customized objects without knowing their exact class or details of how to create them.
Context:
Addresses how to provide a prototype for creating similar object.
Forces:
Create objects without knowing their exact class, how created or what data they represent.
Solution:
Create a prototype class that implements a Prototype interface and are instantiated for being cloned.
Create a prototype builder to supply prototypical objects.
Consequences:
Additional time is spent writing prototypebuilder classes.
CDP - Prototype
SelectSymbol
build symbol object
Suppose you have a CAD system that allows you to draw symbols on a screen from a symbol palette AND you wish to have the user to be able to create user defined symbols.
CDP - Prototype
symbolselection
You have a procedure (set of methods) for each symbol or you have A builder routine for the symbols. Then for a user defined symbol, youmust set up all possible things you might wish and allow the user to select methods at runtime.
user defined symbol selection
SelectSymbol
build symbol selected object
You could allow an object to create a cloned object from others.
CDP - Prototype
symbolselection
The prototype object is built at runtime allowing the user to use thenewly defined symbol based on some predefined prototype.
user defined symbol selection
user defined symbol selection
BuildPrototype
Object
build symbol selected object
CDP - Prototype
CharacterManageruses
Character
Hero Monster
create and register objects
CharacterLoader
<<interface>> Cloneable
PrototypeBuilder
PrototypeClient
CDP - Prototype
import java.awt.Image;
// Abstract class for characters.
public abstract class Character implements Cloneable {
private String name;
private Image image;
private int strength;
//...
// Override clone to make it public. Should never have exception
public Object clone() {
try { return super.clone(); }
catch (CloneNotSupportedException e) {throw new InternalError(); } // try
} // clone()
CDP - Prototype
public String getName() { return name; } // getName()
public void setName(String name) { this.name = name; } // setName(String)
public Image getImage() { return image; } // getImage(Image)
public void setImage(Image image) { this.image = image; } // setImage(Image)
public int getStrength() { return strength; } // getStrength()
public void setStrength(int strength) { this.strength = strength; } // setStrength(int)
//...
} // class Character
CDP - Prototype
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.ObjectInputStream;
// This class loads character objects and adds them to the CharacterManager.
class CharacterLoader {
private CharacterManager mgr;
// Constructor * @param cm The CharacterManager that this object will work with.
CharacterLoader(CharacterManager cm) { mgr = cm; } // Constructor
CDP - Prototype
// Load character objects from specified file.
// Exceptions needed since failure only affects the program when new character objects are not loaded.
// @param fname The name of the file to read objects from.
// @return The number of Charcter objects loaded.
int loadCharacters(String fname) {
int objectCount = 0; // The number of objects loaded
CDP - Prototype // If construction of the InputStream fails, just return
try {
InputStream in;
in = new FileInputStream(fname);
in = new BufferedInputStream(in);
ObjectInputStream oIn = new ObjectInputStream(in);
while(true) {
Object c = oIn.readObject();
if (c instanceof Character) { mgr.addCharacter((Character)c); } // if
} // while
} catch (Exception e) { } // try
return objectCount;
} // loadCharacters(String)
} // class CharacterLoader
CDP - Prototype import java.util.Vector;
// Class manages collection of prototypical objects for the game.
// When asked, it clones appropriate prototypical object and returns it to requesting object.
public class CharacterManager {
private Vector characters = new Vector();
//...
// Return a random character from the collection.
Character getRandomCharacter() {
int i = (int)(characters.size()*Math.random());
return (Character)((Character)characters.elementAt(i)).clone();
} // getRandomCharacter()
CDP - Prototype
// Add a prototypical object to the collection.
// @param character The character to add.
void addCharacter(Character character) {
characters.addElement(character);
} // addCharacter(Character)
//...
} // class CharacterManager
CDP - Prototype // instances of this class are hero characters.
public class Hero extends Character {
private int bravery;
//...
public int getBravery() {
return bravery;
} // getBravery()
public void setBravery(int bravery) {
this.bravery = bravery;
} // setBravery(int)
} // class Hero
CDP - Prototype // instances of this class are monster characters.
public class Monster extends Character {
private int visciousness;
//...
public int getVisciousness() {
return visciousness;
} // getVisciousness()
public void setVisciousness(int visciousness) {
this.visciousness = visciousness;
} // setVisciousness(int)
} // class Monster
CDP - Singleton
Synopsis:
Insures only one instance of a class is created.
Context:
Some classes are used to manage a resource so they require creation only once.
Forces:
Requirement for one instance of a class accessible.
Solution:
A static variable that refers to the one instance of the class you wish to use as a singleton.
Consequences:
Subclassing is awkward and results in imperfectly encapsulated classes.
CDP - Singleton
PlayAudio
audio
Suppose you have a audio connection (player) which plays anAudio but should now allow two audios to play at one time.
CDP - Singleton
audio playtrigger
If you do not want one audio to overlay the others (play at the same time), you will have to write a semaphore to keep multiple audiosfrom playing.
overlaying audio
PlayAudio
audio
Make a singleton which acts as a semaphore to allowcreation of its playing object only once (a singleton).
CDP - Singleton
audio playtrigger
CDP - Singleton
AudioClipManager Singleton
CDP - Singleton import java.applet.AudioClip;
// This class used to avoid playing two audio clips at the same time.
// The class has only one instance accessed through its getInstance method.
// When you play through that object, it stops the last audio clip and starts the new one.
// If all audio clips are played through the AudioClipManager object,
// then there will never be more than one audio clip playing at the same time.
public class AudioClipManager implements AudioClip{
private static AudioClipManager myInstance
= new AudioClipManager();
private AudioClip prevClip; // previously requested audio clip
// Private constructor defined so compiler won't generate a default public constructor.
private AudioClipManager() { }
CDP - Singleton
// Return a reference to the only instance of this class.
public static AudioClipManager getInstance() { return myInstance; } // getInstance()
// Start playing this audio clip. Each time method is called, clip is restarted from beginning.
public void play() { if (prevClip != null) prevClip.play(); } // play()
// Stop previously requested audio clip and play the given audio clip.
// @param clip the new audio clip to play.
public void play(AudioClip clip) {
if (prevClip != null)
prevClip.stop();
prevClip = clip;
clip.play();
} // play(AudioClip)
CDP - Singleton // Starts playing this audio clip in a loop.
public void loop() {
if (prevClip != null) prevClip.loop(); } // loop()
// Stop previously requested audio clip and play the given audio clip in a loop.
// @param clip the new audio clip to play.
public void loop(AudioClip clip) {
if (prevClip != null) prevClip.stop();
prevClip = clip; clip.loop();
} // play(AudioClip)
// Stops playing this audio clip.
public void stop() { if (prevClip != null) prevClip.stop(); } // stop()
} // class AudioClipManager
CDP - Singletonimport java.util.HashSet;
// This class has methods to ensure that an object is never garbage collected.
public class ObjectPreserver implements Runnable {
// This keeps this class and everything it references from being garbage collected
private static ObjectPreserver lifeLine = new ObjectPreserver();
// Since class won't be garbage collected, neither will HashSet or object it references.
private static HashSet protectedSet = new HashSet();
// Constructor.
private ObjectPreserver() { new Thread(this).start(); } // constructor()
public void run() { try { wait(); } catch (InterruptedException e) { } // try } // run()
// Garbage collection of objects passed prevented until sent to unpreserveObject method.
public static void preserveObject(Object o) { protectedSet.add(o); } // preserveObject()
// Objects passed to method lose protection preserveObject method gave from garbage
public static void unpreserveObject(Object o) {protectedSet.remove(o); } // unpreserveO..
} // class ObjectPreserver
CDP - Object Pool
Synopsis:
Manages reuse of objects when a type of object is expensive to create or only a limited number of objects can be created.
Context:
You wish to limit access to a resource
Forces:
A program may not create more than a limited number of instances for a particular class
Solution:
Create a reusable class to collaborate with other objects for a limited amount of time.
Create a reusable pool to manage reusable objects for use by client objects.
Consequences:
Requests may have to wait for an object to become unused.
CDP - Object Pool
Allow DatabaseAccess
database access
Suppose you have a database systems that need to allow only a limited number of accesses to the database at one time.
CDP - Object Pool
database access requested
You must write a counting semaphore to protect this resource from having more than the limited access.
CDP - Object Pool
Clientmanage objects
ReusablePool
uses
Reusable
Reusable Pool
CDP - Object Pool// Public class used outside database access library to represent a database connection.
public class Connection {
private final static ConnectionImpl.ConnectionPool
connectionPool = ConnectionImpl.ConnectionPool.getInstance();
private String databaseName;
//...
// Send a request to the database and return the result.
Object sendRequest(Request request) {
Object result;
ConnectionImpl impl = connectionPool.acquireImpl(databaseName);
result = impl.sendRequest(request);
connectionPool.releaseImpl(impl);
return result;
} // sendRequest(Request)
} // class Connection
CDP - Object Poolimport java.util.Hashtable;
import java.util.Vector;
// Instances of this class provide actual connections to a database.
class ConnectionImpl {
// Name of the datbase this object connected to.
private String dbName;
// Private Constructor
private ConnectionImpl(String dbName) {
this.dbName = dbName;
//...
} // constructor()
//...
// return the name of the database that this objects is connected to.
String getDatabaseName() { return dbName; } // getDatabaseName()
CDP - Object Pool// Send a request to the database and return the result.
Object sendRequest(Request request) {
Object result = null;
//...
return result;
} // sendRequest(Request)
//...
static class ConnectionPool { // The one instance of this class
private static ConnectionPool thePool = new ConnectionPool();
// Hash table associates database names with corresponding Vector that contains
// a pool of connections for that database.
private Hashtable poolDictionary = new Hashtable();
// This constructor is private to prevent other classes from creating instances of this class.
private ConnectionPool() { }
CDP - Object Pool// Return the one instance of this class.
public static ConnectionPool getInstance() { return thePool; } // getInstance()
/**
* Return a ConnectionImpl from appropriate pool or create one if the pool is empty.
* @param dbName Name of database that ConnectionImpl is to be supplied for.
*/
public synchronized ConnectionImpl acquireImpl(String dbName) {
Vector pool = (Vector)poolDictionary.get(dbName);
if (pool != null) {
int size = pool.size();
if (size > 0) return (ConnectionImpl)pool.remove(size-1);
} // if null
// No ConnectionImpl in pool, so create one.
return new ConnectionImpl(dbName);
} // acquireImpl(String)
CDP - Object Pool /**
* Add a ConnectionImpl to the appropriate pool.
*/
public synchronized void releaseImpl(ConnectionImpl impl) {
String databaseName = impl.getDatabaseName();
Vector pool = (Vector)poolDictionary.get(databaseName);
if (pool == null) {
pool = new Vector();
poolDictionary.put(databaseName, pool);
} // if null
pool.addElement(impl);
} // releaseImpl(ConnectionImpl)
} // class ConnectionPool
} // class ConnectionImpl
CDP - Object Pool/**
* Objects used to transmit requests to the database implment this
* interface.
*/
interface Request {
//...
} // interface Request