Паттерн Transaction

Помечено: , ,

В этой теме 0 ответов, 1 участник, последнее обновление  Васильев Владимир Сергеевич 7 мес., 2 нед. назад.

  • Автор
    Сообщения
  • #3620

    Паттерн Transaction это искусственный прием, позволяющий частично обеспечить транзакционность некоторой функциональности. Его можно реализовать, например, следующим образом:

    #include <exception>
    #include <iostream>
    #include <vector>
    #include <boost/shared_ptr.hpp>
    
    class transaction
    {
    public:
    
        transaction()
        : incomplete(true)
        {
        }
    
        ~transaction()
        {
            if(incomplete)
            {
                revert();
            }
        }
    
        template <class T>
        void begin(T& t)
        {
            params.push_back(param_ptr(new param_impl<T>(t)));
        };
    
        void commit()
        {
            incomplete = false;
        }
    
    private:
    
        class param
        {
        public:
    
            virtual ~param() {};
            virtual void revert() const = 0;
        };
    
        template <class T>
        class param_impl : public param
        {
        public:
    
            param_impl(T& t)
            : reference(t)
            , original (t)
            {
            }
    
            virtual void revert() const
            {
                reference = original;
            }
    
        private:
    
            T& reference;
            T  original;
        };
    
        typedef boost::shared_ptr<param> param_ptr;
    
        typedef std::vector<param_ptr> param_container;
    
        bool incomplete;
        param_container params;
    
        void revert()
        {
            for
            (
                param_container::const_reverse_iterator i = params.rbegin();
                i != params.rend();
                ++i
            )
            {
                (*i)->revert();
            }
        }
    };
    
    int main()
    {
        std::string name = "Angelina";
        float bosom  = 85.3f;
        float waist  = 68.5f;
        float pelvis = 88.8f;
    
        try
        {
            transaction trn;
            trn.begin(name);
            trn.begin(bosom);
            trn.begin(waist);
            trn.begin(pelvis);
    
            name   = "Olga";
            bosom  = 102.4f;
            waist  = 59.3f;
            pelvis = 92.3f;
    
            // ...
            // Здесь что-то происходит
            // ...
    
            throw std::runtime_error("Wife is coming!");
    
            trn.commit();
        }
        catch(std::exception const&)
        {
            std::cout << "Hi, dear!" << std::endl;
        }
    
        return 0;
    }

    Достоинство такого подхода заключается в том, что введение транзакции не вынуждает вас вносить какие-то изменения внутрь самого кода. Вы указываете список элементов транзакции в самом начале, и утверждаете внесенные изменения в самом конце. В сам код никаких изменений вносить не нужно.

    Главным недостатком, который, по сути, делает этот паттерн практически не применимым в реальной жизни, является тот факт, что даже глубинного копирования объекта не достаточно, чтобы последующий откат его значения откатывал все изменения, которые этот объект внес в систему. То есть, если объект внутри себя вызвал какую-то свободную функцию, которая, в свою очередь, внесла какие-то изменения во внешние данные, то эти изменения будет невозможно отследить в автоматическом режиме и откатить в случае, если транзакция не прошла.

    Старайтесь обеспечивайть транзакционное поведение естественными описанием типов и реализацией функциональности, а не искусственными приемами.

Для ответа в этой теме необходимо авторизоваться.