SDSU CS 596: Client Server Programming
Design Patterns

[To Lecture Notes Index]
San Diego State University -- This page last updated February 13, 1995
----------

Contents of Design Patterns Lecture

Introduction to Libraries

  1. Introduction to Libraries
  2. References for Lecture
  3. Design Pattern
    1. State Pattern
    2. Singleton Pattern

References for Lecture

Berard, Edward. Essays on Object-Oriented Software Engineering Vol 1, Prentice-Hall, 1993, chapter 6

Johnson, Ralph and Zweig, Jonathan, "Delegation in C++", Journal of Object-Oriented Programming, November/December 1991, pp 31-34

Gamma, Helm, Johnson, Vlissides Designs Patterns: Elements of Reusable Object-Oriented Software, Addision-Wesley, 1995

Parnas, D. L., "On the Criteria To Be Used in Decomposing Systems into Modules," Communications of the ACM, Vol. 5, No. 12, December 1972, pp. 1053-1058.


Abstraction

"Extracting the essential details about an item or group of items, while ignoring the unessential details."

Edward Berard

"The process of identifying common patterns that have systematic variations; an abstraction represents the common pattern and provides a means for specifying which variation to use."

Richard Gabriel

Pattern:
Priority queue
Essential Details:
length
items in queue
operations to add/remove/find item
Variation:
link list vs. array implementation
stack, queue

Abstraction can provide a different view of details

TCP
Information Hiding

"The technique of encapsulating software design decisions in modules in such a way that the module's interface reveals as little as possible about the module's inner workings; thus each module is a "black box" to the other modules in the system"

IEEE publication

Information hiding can be used to hide details of the procedural steps necessary to accomplish a task.

"We propose instead that one begins with a list of difficult design decisions or design decisions which are likely to change. Each module is then designed to hide such a decision from others"

Parnas 1972

Abstraction is the purpose of hiding information

Encapsulation

Enclosing all parts of an abstraction within a container

How one hides information


C++ Class
class SampleClassFormat {

public:

	int PublicVariable;

	int PublicFunction(float argument);

protected:

	int ProtectedVariable;

	int ProtectedFunction(float argument);

private:

	int PrivateVariable;

	int PrivateFunction(float argument);

	static int OneCopy;
};

int SampleClassFormat::OneCopy = 10;

int SampleClassFormat::PublicFunction(float argument) 
{
	OneCopy = argument;
	return 5;
};

Things to Understand

Design Pattern

"Each pattern describes a problem which occurs over and over again in our environment, and then describes the core of the solution to that problem, in such a way that you can use this solution a million times over, without ever doing it the same way twice"

Christopher Alexander

A pattern has four essential elements:

Pattern Name
Problem
Solution
Consequences

Notation

Modified OMT notation for classes and relationships


Pseudocode Notation


Notation - Relationships


State Pattern

Intent

Allow an object to alter its behavior when its internal state changes

Motivation - TCPConnection class

TCPConnection object has different states:

Established
Listening
Closed
TCPConnection object reacts to operations differently depending on what state it is in
Applicability

Use the state pattern when:

  • Object's behavior depends on its state, and must change its state at run-time
  • Operations have large, multipart conditional statements that depend on the object's state

Structure of State Pattern

Context (TCPConnection)
defines interface used by clients
maintains an instance of a ConcreteState that defines the current state
State (TCPState)
defines an interface for encapsulating the behavior associated with a particular state of the Context
ConcreteState subclasses (TCPEstablished, TCPListen,...)
each subclass implements a behavior associated with a state of the Context

TCP Example
class TCPState;

class TCPConnection {
public:
	TCPConnection();
	~TCPConnection();

	int ActiveOpen();
	int PassiveOpen();
	int Close();
	int Transmit(TCPMessage*);

private:
	friend class TCPState;
	void ChangeState(TCPState*);

private:
	TCPState* state;
	// other stuff not shown
};

TCPConnection::TCPConnection()  {
	state = TCPClosed::Instance();
}

void TCPConnection::ChangeState(TCPState* newState) {
	state = newState;
}

int TCPConnection::ActiveOpen() {
	return  state->ActiveOpen(this);
}

class TCPState {
public:

	virtual int ActiveOpen( TCPConnection* );
	virtual int PassiveOpen( TCPConnection* );
	virtual int Close( TCPConnection* );
	virtual int Transmit( TCPConnection*, TCPMessage*);

protected:
	void ChangeState(TCPConnection*, TCPState*);
};

//Default behavior for all requests

int TCPState :: ActiveOpen( TCPConnection* ) {  };
int TCPState :: PassiveOpen( TCPConnection* )  {  };
int TCPState :: Close( TCPConnection* )  {  };
int Transmit( TCPConnection*, TCPMessage*) {  };

void TCPState :: ChangeState(TCPConnection* connection,
							TCPState * newState) {

connection -> ChangeState(newState);
}
class TCPClosed : public TCPState {

public:

	static TCPState*  Instance();

	virtual int ActiveOpen( TCPConnection* );
	virtual int PassiveOpen( TCPConnection* );
	virtual int Close( TCPConnection* );
	// etc.
};


int TCPClosed :: ActiveOpen( TCPConnection*  connection) {

	// do the actual work to open an active socket here

	ChangeState(connection, TCPEstablished::Instance());
}


Consequences of State Pattern



Alternative:
Variables to indicate current state
Use case statements to determine proper behavior

Often State objects need no data members, so can be shared

Implementation Issues of State Pattern
State
More flexible
Context
Can be done if criteria for changing state is fixed
state                   Input A                 Input B                 Input C                 
state 1                 state 3                 state 2                 state 1                 
state 2                 state 2                 state 1                 state 3                 
state 3                 state 1                 state 2                 state 1                 

Can change state transitions by changing data (table)
Table look-up is often less efficient
Transition criteria is less explicit
Hard to add actions to transitions
Create object only when needed, destroy when done
Create them ahead of time, never destroy

Singleton Pattern

Intent

Ensure a class has only one instance

Provide a global point of access to the single instance

Applicability

Use this pattern when:


Implementation of Singleton
class Singleton {

public:

	static Singleton* Instance();

protected:

	Singleton();

private:

	static Singleton* _instance;
};


Singleton* Singleton :: _instance = 0;


Singleton* Singleton :: Instance () {

	if ( _instance  == 0)	_instance  = New Singleton;

	return _instance ;
}

Implementation- Subclassing the Singleton
class Singleton {

public:
	static void Register(char* name, Singleton*);
	static Singleton* Instance(char* name);

protected:
	static Singleton* Lookup(const char* name);

private:
	static Singleton* _instance;
	static List<NameSingletonPair>* _registry;
};


Singleton* Singleton :: _instance = 0;


Singleton* Singleton :: Instance (char* name) {

	if ( _instance  == 0) {

		_instance = Lookup( name );  
							//Returns 0 if no such instance

	}
	return _instance ;
}

Implementation- Subclassing the Singleton Cont.

class FooSingleton : public Singleton {
public:

	FooSingleton();

}

FooSingleton :: FooSingleton() {

	Singleton :: Register("FooSingleton", this );
}

// in implementation file

static FooSingleton  barSingleton;