Creational Patterns

Download Report

Transcript Creational Patterns

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 - Example
You 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.
CDP - Factory Method - Example
Manage
Doc
Files
doc file commands
xls file commands
Manage
Xls
Files
ppt file commands
file commands
Manage
Files
Manage
Ppt
Files
Make
one Function
CDP - Factory Method - Example
Document
MyDocument
edits
*
1
Application
May be doc,
xls, or ppt.
CDP - Factory Method - Example
Document
edits
*
1
Application
Requests creation
creates
DocumentFactoryIF
MyDocument
DocumentFactory
CDP - Factory Method - Example
Suppose you have a process which reads and writes
a DataStream to a socket.
string
Write to
Socket
stream
Socket
string
Read from
Socket
stream
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.
CDP - Factory Method - Example
encrypted
string
string
Encrypt
Data
decrypted
string
Decrypt
Data
Write to
Encrypted
Socket
encrypted
string
encrypted
string
encrypted
stream
Write to
Encrypted
Socket
Read from
Socket
EncryptedSocket
encrypted
stream
encrypted
stream
EncryptedSocket
Socket
But now you realize that there are several different encryption
algorithms and codes you wish to use.
CDP - Factory Method - Example
The process to encrypt differs in using many different different
algorithms (function/method) and type of string output must be
written for each type.
string
Encrypt
Data
encrypted
String #1
Write to
Encrypted
Socket
algorithm # 1
string
Encrypt
Data
encrypted
String #2
Write to
Encrypted
Socket
encrypted
stream
encrypted
stream
EncryptedSocket
EncryptedSocket
algorithm # 2
string
algorithm # n
Encrypt
Data
encrypted
String #n
Write to
Encrypted
Socket
encrypted
stream
EncryptedSocket
CDP - Factory Method - Example
The factory pattern allows you to have a framework that will
handle any type of algorithm and encrypted data.
concrete
product
string
encrypted
String
Encrypt
Data
algorithm # 1
algorithm # n
algorithm # 2
Write to
Encrypted
Socket
encrypted
stream
EncryptedSocket
CDP - Factory Method - Example
Socket
Socket
4
Product
6
encrypt, decrypt
Encryption
1
EncryptedSocket
1
*
Creation Requester
DESEncryption
1
5
*
Concrete Product
Transcription
*
1
creates
1
EncryptedSocket
creates
EncryptionFactory
3
Factory
EncryptionFactoryIF
2
* requestCreation
Interface
CDP - Factory Method - Example
Socket
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
Encryption
encrypt, decrypt
1
EncryptedSocket
1
*
DESEncryption
*
Transcription
*
import java.net.Socket;
creates
import java.security.Key;
1
creates
1
EncryptionFactory
EncryptionFactoryIF
* requestCreation
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;
CDP - Factory Method - Example
Socket
Encryption
encrypt, decrypt
1
EncryptedSocket
1
*
DESEncryption
*
Transcription
*
// Constructor
creates
// @param Key for encryption and decryption.
1
creates
1
EncryptionFactory
EncryptionFactoryIF
* requestCreation
// 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)
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
Socket
Encryption
import java.io.InputStream;
import java.io.OutputStream;
encrypt, decrypt
1
1
*
DESEncryption
*
Transcription
import java.security.Key;
*
creates
// Abstract class to encrypt/decrypt streams of bytes.
1
creates
1
EncryptionFactory
EncryptionFactoryIF
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()
EncryptedSocket
* requestCreation
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
Socket
Encryption
encrypt, decrypt
1
EncryptedSocket
1
*
DESEncryption
*
import java.security.Key;
import java.security.NoSuchAlgorithmException;
Transcription
*
creates
1
creates
1
EncryptionFactory
EncryptionFactoryIF
// This interface must be implemented by all factory classes
* requestCreation
// 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
CDP - Factory Method - Example
Socket
Encryption
encrypt, decrypt
1
EncryptedSocket
1
*
DESEncryption
*
Transcription
*
creates
creates
1
EncryptionFactory
1
EncryptionFactoryIF
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 {
* requestCreation
CDP - Factory Method - Example
Socket
Encryption
encrypt, decrypt
1
EncryptedSocket
1
*
DESEncryption
*
Transcription
*
// Returns an instanace of the appropriate subclass of Encryption.
creates
// It is determined by the given Key object's getAlgorithm method.
1
creates
1
EncryptionFactory
EncryptionFactoryIF
* requestCreation
// @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
CDP - Factory Method - Example
Socket
Encryption
import java.io.InputStream;
import java.io.FilterInputStream;
encrypt, decrypt
1
EncryptedSocket
1
*
DESEncryption
*
Transcription
import java.io.FilterOutputStream;
*
creates
import java.io.OutputStream;
1
creates
1
EncryptionFactory
EncryptionFactoryIF
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)
* requestCreation
CDP - Factory Method - Example
Socket
Encryption
encrypt, decrypt
1
EncryptedSocket
1
*
DESEncryption
*
Transcription
*
creates
1
creates
1
EncryptionFactory
EncryptionFactoryIF
// 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)
* requestCreation
CDP - Factory Method - Example
Socket
Encryption
encrypt, decrypt
1
EncryptedSocket
1
*
DESEncryption
*
Transcription
*
creates
1
creates
1
EncryptionFactory
EncryptionFactoryIF
/**
* 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)
* requestCreation
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.
CDP - Abstract 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 - Abstract Factory Method
Suppose you have a textfield or any other GUI component
and you wish to display it on a particular platform.
windows textfield
Display
CDP - Abstract Factory Method
Suppose you wish to display those GUI components
on various platforms.
windows textfield
Display
MacOS textfield
Linix textfield
Certainly each platform expects to see different
Java byte code.
CDP - Abstract Factory Method
Request services
Client
1
uses
uses
Abstract Factory
CPU
Architecture Toolkit
uses
creates
Concrete Factory
EmberCPU
Concrete Product
EmberToolkit
EnginolaCPU
*
EnginolaToolkit
*
1
creates
MMU
creates
EnginolaMMU
requestCreation
EmberMMU
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() {
//...
} // class EmberToolkit
return new EmberMMU();
} // createMMU()
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() {
//...
} // class EnginolaToolkit
return new EnginolaMMU();
} // createMMU()
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.
CDP - Builder
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
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.
MIME
mail
Forward
E-mail
format 1
Destination 1
format 2
Destination 1
format 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.
CDP - Builder
You want a class to build the format needed depending on the
Destination using a builder class.
MIME
mail
Build
Format
format
whatever
Forwarded
E-Mail
Destination 1
Destination 1
Destination 1
CDP - Builder
1: receive(MIME)
Director
manages
MessageManager
MIMEMsg
sends
2: parse(MIME)
is parsed by
ProductIF
OutboundMessageIF
4: send
MIMEParser
PRoFMsg
*
Product
directs
MAPIMsg
*
1
3: build
creates
MessageBuilder
creates
MAPIBuilder
requestCreation
PROFSBuilder
CDP - Builder
(collaboration diagram)
2: parse(MIME)
1: receive(MIME)
1.1: outMsg:=parse(msg:MIMEMsg)
1: receive (msg:MIMEMsg)
MessageManager
MIMEParser
1.2: send( )
outMsg:OutboundMessageIF
4: send
MessageBuilder
3: build
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)
Builder:MAPIBuilder
CDP - Builder
import 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)
1: receive (msg:MIMEMsg)
MessageManager
1.1: outMsg:=parse(msg:MIMEMsg)
MIMEParser
2: parse(MIME)
1: receive(MIME)
1.2: send( )
outMsg:OutboundMessageIF
4: send
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( )
3: build
MessageBuilder
1.1.1: builder:=getInstance(to:String)
Builder:MAPIBuilder
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() {
} // class MIMEMessage
return rawMessage;
} // getMessage()
CDP - Builder
1: receive (msg:MIMEMsg)
MessageManager
1.1: outMsg:=parse(msg:MIMEMsg)
MIMEParser
2: parse(MIME)
1: receive(MIME)
1.2: send( )
outMsg:OutboundMessageIF
4: send
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( )
3: build
MessageBuilder
1.1.1: builder:=getInstance(to:String)
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
//...
Builder:MAPIBuilder
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
1: receive (msg:MIMEMsg)
MessageManager
1.1: outMsg:=parse(msg:MIMEMsg)
MIMEParser
2: parse(MIME)
1: receive(MIME)
1.2: send( )
outMsg:OutboundMessageIF
4: send
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( )
3: build
MessageBuilder
1.1.1: builder:=getInstance(to:String)
Builder:MAPIBuilder
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.
CDP - Prototype
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
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.
symbol
selection
user defined
symbol selection
Select
Symbol
build symbol object
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, you
must set up all possible things you might wish and allow the user to
select methods at runtime.
CDP - Prototype
You could allow an object to create a cloned object from others.
symbol
selection
user defined
symbol selection
Select
Symbol
build symbol selected object
user defined
symbol selection
Build
Prototype
Object
build symbol selected object
The prototype object is built at runtime allowing the user to use the
newly defined symbol based on some predefined prototype.
CDP - Prototype
<<interface>> Cloneable
Prototype
Client
uses
CharacterManager
Character
create and register objects
CharacterLoader
PrototypeBuilder
Hero
Monster
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();
} // clone()
} // try
CDP - Prototype
public String getName() {
return name;
public void setName(String name) {
public Image getImage() {
public int getStrength() {
this.name = name;
return image;
public void setImage(Image image) {
} // getName()
} // getImage(Image)
this.image = image;
return strength;
} // setName(String)
} // setImage(Image)
} // getStrength()
public void setStrength(int strength) { this.strength = strength;
//...
} // class Character
} // setStrength(int)
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);
} // while
} catch (Exception e) {
return objectCount;
} // loadCharacters(String)
} // class CharacterLoader
} // try
} // if
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.
CDP - Singleton
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
Suppose you have a audio connection (player) which plays an
Audio but should now allow two audios to play at one time.
audio play
trigger
Play
Audio
audio
overlaying audio
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 audios
from playing.
CDP - Singleton
Make a singleton which acts as a semaphore to allow
creation of its playing object only once (a singleton).
audio play
trigger
Play
Audio
audio
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)
} // class AudioClipManager
prevClip.stop();
} // stop()
CDP - Singleton
import 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
CDP - Object Pool
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
Suppose you have a database systems that need to allow only a
limited number of accesses to the database at one time.
database access requested
Allow
Database
Access
database access
You must write a counting semaphore to protect this resource from
having more than the limited access.
CDP - Object Pool
manage objects
Client
uses
Reusable
ReusablePool
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 Pool
import 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