Creational Design Patterns Factory Method Abstract Factory Builder Prototype Singleton Object Pool.

Post on 18-Jan-2016

224 views 0 download

Tags:

Transcript of Creational Design Patterns Factory Method Abstract Factory Builder Prototype Singleton Object Pool.

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.

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

stringWrite to

EncryptedSocket

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

creates1

1

*

*

*

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 Factory

Concrete 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

sends

is 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 - 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)

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 - 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

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 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