Structural

Adapter (Wrapper)

Purpose

Convert the incompatible interface of a class into another interface compatible with clients.

UML

Behavior

A client calls operations on an adapter object, which in turn forwards the call on to the adaptee.

Example

The interface of std::deque<T> is (partially) adapted to support the interface of a queue. A queue typically supports, among other operations, push, pop, front and back operations. Whereas std::deque<> supports, among others,  push_front, push_back, pop_font, pop_back, etc. Note how Queue<T>::push(x) calls std::deque<T>::push_back(x).

Usage

/* Adapter: Adapts the interface of adaptee to an interface acceptable by the client In this example, the client expects a queue to support push, pop, front, and back operations. A std::deque is therefore adapted to the behavior of a queue by wrapping the deque operations with the expected interface. */

template<typename T>
class Queue
{
// Public Interface
public:
    void push( const T& x)
    {
        m_deque.push_back( x );
    }
    T pop()
    {
        // Check container is not empty
        if (m_deque.empty())
            throw QueueEmpty();

        // Get first element from deque and pop it form the front
        T element( m_deque.front() );
        m_deque.pop_front();

        return element;
    }
    T& front()
    {
        // Check container is not empty
        if (m_deque.empty())
            throw QueueEmpty();

        return m_deque.front();
    }
    T& back()
    {
        // Check container is not empty
        if (m_deque.empty())
            throw QueueEmpty();

        return m_deque.back();
    }

// Data members
private:
    std::deque<T> m_deque;
};

class QueueEmpty : std::exception
{
public:
    virtual const char *what() const throw()
    {
        return "Queue is empty";
    }
};

int main(int argc, char* argv[])
{
    try
    {
        // Push 3 items
        Queue<int> q;
        q.push( 10 );
        q.push( 20 );
        q.push( 30 );

        std::cout << "front is: " << q.front() << std::endl;
        std::cout << "back is: " << q.back() << std::endl;

        // Pop 4 items
        q.pop();
        q.pop();
        q.pop();
        q.pop(); // throws exception. Queue is empty
    }
    catch( const QueueEmpty& e)
    {
        std::cout << e.what();
    }

    return 0;
}

Notes