behavioral

Command (Action, Transaction)

Purpose

Encapsulate a method invocation as an object.

UML

Behavior

A client creates a command object and specifies its receiver (the object on which to invoke an method). The command object can be passed around like any other object (even to other threads/address spaces - more on this later), but typically the command object is stored inside an invoker object, which, when required, issues a request by calling Execute() on the command object. The command object invokes operations on its receiver object to carry out the request.

Example

In the following example, the Command pattern is used in cross-thread communication to realize asynchronous method calls; Each time the main thread needs to execute a lengthy operation it creates a command object that wraps this lengthy operations, and pushes it  into a queue. The main thread is now free to resume normal execution. The other thread, called the working thread, pops these command objects out of the queue and executes them sequentially.

With the Command pattern, the worker thread is decoupled from the command object; The worker thread knows nothing about the command object and what it does. The worker thread needs only to execute each command object using the same syntax:
    pCmdObject->Execute();

Usage

/* Command Classes */

/* Command: Declares an interface for executing an operation */
template< typename RetValue = int>
class CCommand
{
//Constructor/Destructors
public:
    virtual ~CCommand(){} // always a virtual destructor for a base class
protected:
    /* protected: gives compiler error if users attempt to create an instance of
    this class (cannot be private because derived classes wont be able to call it,
    can be public but protected gives an extra insurance) */
    CCommand(){}

// Public interface
public:
    virtual RetValue Execute() = 0;
};

/* Concrete Command: Defines a bridging between the receiver object and an action. It implements the Execute operation by invoking the corresponding operation on the receiver.*/
template<typename ReceiverPtr, typename MemberFunPtr, typename Param1, typename RetValue = int>
class OneArgumentCommand : public CCommand<RetValue>
{
// Constructors
public:
    /* Initialize receiver object, its member function, and the single argument
    Reminder: we can init a non-const pointer with a const pointer, and vice versa, 
    we can init a const pointer with a non-const pointer */
    OneArgumentCommand( const ReceiverPtr pR, const MemberFunPtr pMF, const Param1 p1):
        m_pObject( pR ), m_pFun( pMF ), m_Param1( p1 ) {}

// Public interface
public:
    RetValue Execute()
    {
        if ( !m_pObject || !m_pFun ) 
            throw std::invalid_argument("Invalid pointers");

        // Replace the following with : ((*m_pObject).*m_pFun)(m_Param1)
        // to allow smart pointers for objects (smart pointer may not support ->* )
        (m_pObject->*m_pFun)(m_Param1);

        return RetValue(); // for now, return default value of the return value type
    }

// Data members
private:
    ReceiverPtr    m_pObject;
    MemberFunPtr   m_pFun;
    Param1         m_Param1;
};

/* Concrete Command class: Used for executing receiver methods that take two arguments */
template<typename ReceiverPtr, typename MemberFunPtr, typename Param1, typename Param2,
         typename RetValue = int>
class TwoArgumentCommand : public CCommand<RetValue>
{
// Constructors
public:
    /* Initialize receiver object, its member function, and its two arguments */
    TwoArgumentCommand( const ReceiverPtr pR, const MemberFunPtr pMF, 
                        const Param1 p1, const Param2 p2):
        m_pObject(pR), m_pFun(pMF), m_Param1(p1), m_Param2(p2) {}

// Public interface
public:
    RetValue Execute()
    {
        if ( !m_pObject || !m_pFun ) 
            throw std::invalid_argument("Invalid pointers");

        (m_pObject->*m_pFun)(m_Param1, m_Param2);

        return RetValue(); // for now, return default value of the return value type
    }

// Data members
private:
    ReceiverPtr  m_pObject;
    MemberFunPtr m_pFun;
    Param1       m_Param1;
    Param2       m_Param2;
};

/* Use OneArgumentCommand class as a model to supply concrete command classes for executing receiver methods that take a different number of arguments */
template<typename ReceiverPtr, typename MemberFunPtr, typename Param1, typename Param2,
         typename Param3, typename RetValue = int>
class ThreeArgumentCommand : public CCommand<RetValue>
{
    ... 
};

template<typename ReceiverPtr, typename MemberFunPtr, typename Param1, typename Param2,
         typename Param3, typename Param4, typename RetValue = int>
class FourArgumentCommand : public CCommand<RetValue>
{
    ... 
};

class CPrint
{
public:
    void PrintHighRes( int nPages )
    {
        std::cout << "PrintHighRes(): Perform a lengthy operation ..." << std::endl;

        // Lengthy calculations ...
    }
    void PrintHighResWithCopies( int nPages, long lNoOfCopies )
    {
        std::cout << "PrintHighResWithCopies(): Perform a lengthy operation ...";
        std::cout << std::endl;

        // Lengthy calculations ...
    }
};

int main(int argc, char* argv[])
{
    // Note the second argument in the typedef: a pointer to a member function taking an
    // int and returning a void.
    typedef OneArgumentCommand<CPrint*, void(CPrint::*)(int), int, double>
            ONE_ARG_COMMAND;

    typedef TwoArgumentCommand<CPrint*, void(CPrint::*)(int, long), int, long, std::string> 
            TWO_ARG_COMMAND;

    /* Thread 1 */
    // Create command objects that perform lengthy operations. The command object
    // can then be pushed into a queue where a worker thread can pop and execute.
    CPrint obPrint;
    CCommand<double>      *pCmd1 = new ONE_ARG_COMMAND( &obPrint, &CPrint::PrintHighRes, 10);
    CCommand<std::string> *pCmd2 = new TWO_ARG_COMMAND( &obPrint, &CPrint::PrintHighResWithCopies, 10,5);

        // Push command objects into queue ...

    /* Thread 2 */
    // Pops the command object from the queue and executes it. There might be tens of 
    // these command objects in the queue, keeping the worker thread busy while the main
    // thread is doing other things.
    try
    {
        // Pop command object from queue ...

        int nRet        = pCmd1->Execute();
        std::string str = pCmd2->Execute();
    }
    catch( const std::exception& e)
    {
        std::cout << e.what() << std::endl;
    }
    return 0;
}

Notes