4. Which design pattern is used in the following code?

#include <algorithm>
#include <cassert>
#include <iterator>
#include <list>
#include <map>
#include <sstream>
#include <string>
#include <utility>

class Task
{
public:
    typedef std::map<std::string, std::string> Arguments;

public:
    bool solve(const Arguments &input, Arguments &output)
    {
        assert(output.empty());

        if (!read_input(input)) {
            return false;
        }
        if (!operate()) {
            return false;
        }
        write_output(output);

        return true;
    }

protected:
    virtual bool read_input(const Arguments &input) = 0;
    virtual bool operate() = 0;
    virtual void write_output(Arguments &output) const = 0;

public:
    virtual ~Task() { }
};

class ArithmeticTask
    : public Task
{
public:
    ArithmeticTask()
        : m_x(0)
        , m_y(0)
        , m_operation(0)
        , m_result(0)
    { }

private:
    bool read_input(const Arguments &input)
    {
        Arguments::const_iterator i = input.find("x");
        if (input.end() == i) {
            return false;
        }
        std::istringstream in(i->second);
        in >> m_x;
        if (in.fail()) {
            return false;
        }

        i = input.find("y");
        if (input.end() == i) {
            return false;
        }
        in.clear();
        in.str(i->second);
        in >> m_y;
        if (in.fail()) {
            return false;
        }

        i = input.find("operation");
        if (input.end() == i || i->second.size() != 1) {
            return false;
        }
        m_operation = i->second[0];

        return true;
    }

    bool operate()
    {
        switch (m_operation)
        {
            case '+':
                m_result = m_x + m_y;
                break;
            case '-':
                m_result = m_x - m_y;
                break;
            case '*':
                m_result = m_x * m_y;
                break;
            case '/':
                if (0 == m_y) {
                    return false;
                }
                m_result = m_x / m_y;
                break;
            default:
                return false;
        }

        return true;
    }

    void write_output(Arguments &output) const
    {
        std::ostringstream out;
        out << m_result;
        output.insert(std::make_pair(std::string("result"), out.str()));
    }

private:
    int m_x;
    int m_y;
    char m_operation;
    int m_result;
};

class ReverseTask
    : public Task
{
private:
    bool read_input(const Arguments &input)
    {
        m_array.clear();

        Arguments::const_iterator i = input.find("array");
        if (input.end() == i) {
            return false;
        }
        std::istringstream in(i->second);
        typedef std::istream_iterator<int> T;
        std::copy(T(in), T(), std::back_inserter(m_array));
        if (!in.eof()) {
            return false;
        }

        return true;
    }

    bool operate()
    {
        m_array.reverse();

        return true;
    }

    void write_output(Arguments &output) const
    {
        std::ostringstream out;
        std::copy(m_array.begin(), m_array.end(),
                  std::ostream_iterator<int>(out, " "));
        output.insert(std::make_pair(std::string("result"), out.str()));
    }

private:
    std::list<int> m_array;
};