CS 596: Client Server Programming
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.
"Extracting the essential details about an item or group of items, while ignoring the unessential details."
"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."
Abstraction can provide a different view of details
"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"
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"
Abstraction is the purpose of hiding information
Enclosing all parts of an abstraction within a container
How one hides information
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;
};
"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"
A pattern has four essential elements:
Modified OMT notation for classes and relationships
Notation - Relationships
Allow an object to alter its behavior when its internal state changes
TCPConnection object has different states:
Use the state pattern when:
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());
}
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
Ensure a class has only one instance
Provide a global point of access to the single instance
Use this pattern when:
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 ;
}
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 ;
}
class FooSingleton : public Singleton {
public:
FooSingleton();
}
FooSingleton :: FooSingleton() {
Singleton :: Register("FooSingleton", this );
}
// in implementation file
static FooSingleton barSingleton;