C++ Programming/Code/Design Patterns/Behavioral Patterns
From Wikibooks, the open-content textbooks collection
Contents |
[edit] Behavioral Patterns
[edit] Chain of Responsibility
Chain of Responsibility pattern has the intent to avoid coupling the sender of a request to its receiver by giving more then one object a chance to handle the request. Chains the receiving objects and passes the requests along the chain until an object handles it.
[edit] Command
Command pattern is an Object behavioral pattern that decouples sender and receiver by encapsulating a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations. It can also be thought as an object oriented equivalent of call back method.
Call Back: It is a function that is registered to be called at later point of time based on user actions.
[edit] Interpreter
Given a language, define a representation for its grammar along with an interpreter that uses the representation to interpret sentences in the language.
[edit] Iterator
The 'iterator' design pattern is used liberally within the STL for traversal of various containers. The full understanding of this will liberate a developer to create highly reusable and easily understandable data containers.
The basic idea of the iterator is that it permits the traversal of a container (like a pointer moving across an array). However, to get to the next element of a container, you need not know anything about how the container is constructed. This is the iterators job. By simply using the member functions provided by the iterator, you can move, in the intended order of the container, from the first element to the last element.
Let's start by considering a traditional single dimensional array with a pointer moving from the start to the end. This example assumes knowledge of pointer arithmetic. Note that the use of "it" or "itr," henceforth, is a short version of "iterator."
const int ARRAY_LEN = 42; int *myArray = new int[ARRAY_LEN]; // Set the iterator to point to the first memory location of the array int *arrayItr = myArray; // Move through each element of the array, setting it equal to its position in the array for(int i = 0; i < ARRAY_LEN; ++i) { // set the value of the current location in the array *arrayItr = i; // by incrementing the pointer, we move it to the next position in the array. // This is easy for a contiguous memory container, since pointer arithmetic // handles the traversal. ++arrayItr; } // Don't be messy, clean up after yourself delete[] myArray;
This code works very quickly for arrays, but how would we traverse a linked list, when the memory is not contiguous? Consider the implementation of a rudimentary linked list as follows:
class IteratorCannotMoveToNext{}; // Error class class MyIntLList { public: // The Node class represents a single element in the linked list. // The node has a next node and a previous node, so that the user // may move from one position to the next, or step back a single // position. Notice that the traversal of a linked list is O(N), // as is searching, since the list is not ordered. class Node { public: Node():mNextNode(0),mPrevNode(0),mValue(0){} Node *mNextNode; Node *mPrevNode; int mValue; }; MyIntLList():mSize(0) {} ~MyIntLList() { while(!Empty()) pop_front(); } // See expansion for further implementation; int Size() const {return mSize;} // Add this value to the end of the list void push_back(int value) { Node *newNode = new Node; newNode->mValue = value; newNode->mPrevNode = mTail; mTail->mNextNode = newNode; mTail = newNode; ++mSize; } // Remove the value from the beginning of the list void pop_front() { if(Empty()) return; Node *tmpnode = mHead; mHead = mHead->mNextNode delete tmpnode; --mSize; } bool Empty() {return mSize == 0;} // This is where the iterator definition will go, // but lets finish the definition of the list, first private: Node *mHead; Node *mTail; int mSize; };
This linked list has non-contiguous memory, and is therefore not a candidate for pointer arithmetic. And we dont want to expose the internals of the list to other developers, forcing them to learn them, and keeping us from changing it.
This is where the iterator comes in. The common interface makes learning the usage of the container easier, and hides the traversal logic from other developers.
Let's examine the code for the iterator, itself.
/*
* The iterator class knows the internals of the linked list, so that it
* may move from one element to the next. In this implementation, I have
* chosen the classic traversal method of overloading the increment
* operators. More thorough implementations of a bi-directional linked
* list would include decrement operators so that the iterator may move
* in the opposite direction.
*/
class Iterator
{
public:
Iterator(Node *position):mCurrNode(position){}
// Prefix increment
const Iterator &operator++()
{
if(mCurrNode == 0 || mCurrNode->mNextNode == 0)
throw IteratorCannotMoveToNext();e
mCurrNode = mCurrNode->mNextNode;
return *this;
}
// Postfix increment
Iterator operator++(int)
{
Iterator tempItr = *this;
++(*this);
return tempItr;
}
// Dereferencing operator returns the current node, which should then
// be dereferenced for the int. TODO: Check syntax for overloading
// dereferencing operator
Node * operator*()
{return mCurrNode;}
// TODO: implement arrow operator and clean up example usage following
private:
Node *mCurrNode;
};
// The following two functions make it possible to create
// iterators for an instance of this class.
// First position for iterators should be the first element in the container.
Iterator Begin(){return Iterator(mHead);}
// Final position for iterators should be one past the last element in the container.
Iterator End(){return Iterator(0);}
With this implementation, it is now possible, without knowledge of the size of the container or how its data is organized, to move through each element in order, manipulating or simply accessing the data. This is done through the accessors in the MyIntLList class, Begin() and End().
// Create a list MyIntLList mylist; // Add some items to the list for(int i = 0; i < 10; ++i) myList.push_back(i); // Move through the list, adding 42 to each item. for(MyIntLList::Iterator it = myList.Begin(); it != myList.End(); ++it) (*it)->mValue += 42;
[edit] Mediator
Define an object that encapsulates how a set of objects interact. Mediator promotes loose coupling by keeping objects from referring to each other explicitly, and it lets you vary their interaction independently.
[edit] Memento
Without violating encapsulation the memento Pattern will capture and externalize an object’s internal state so that the object can be restored to this state later. Though the Gang of Four uses friend as a way to implement this pattern it is not the best design. It can also be implemented using PIMPL. Best Use case is 'Undo-Redo' in an editor.
[edit] Observer
The Observer Pattern defines a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.
- Problem
- In one place or many places in the application we need to be aware about a system event or an application state change. We'd like to have a standard way of subscribing to listening for system events and a standard way of notifying the interested parties. The notification should be automated after an interested party subscribed to the system event or application state change. There also should be a way to unsubscribed.
- Forces
- Observers and observables probably should be represented by objects. The observer objects will be notified by the observable objects.
- Solution
- After subscribing the listening objects will be notified by a way of method call.
[edit] State
The State Pattern allows an object to alter its behavior when its internal state changes. The object will appear as having changed its class.
[edit] Strategy
Defines a family of algorithms, encapsulates each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients who use it.
[edit] Template Method
By defining a skeleton of an algorithm in an operation, deferring some steps to subclasses, the Template Method lets subclasses redefine certain steps of that algorithm without changing the algorithms structure.
[edit] Visitor
The Visitor Pattern will represent an operation to be performed on the elements of an object structure by letting you define a new operation without changing the classes of the elements on which it operates.
[edit] Model-View-Controller (MVC)
pattern often used by applications that need the ability to maintain multiple views of the same data.