• 一个实现恢复删除机制(do undo)的设计


    BaseOperation.h

    /*----------------------------------------------------------
    desc    : 编辑器中各种操作的接口类。
    author    : zilong
    version    : 1.0
    date    : 2011-03-23

    revision:

    ----------------------------------------------------------*/

    #pragma once

    class IBaseOperation
    {
    public:
        IBaseOperation(void);
        virtual ~IBaseOperation(void);

        //每个operation应该保证在没有成功的情况下自己回滚(即不改变数据库)。
        virtual bool Excute(void) = 0;

        void SetStatus(bool bExcuted_);

    protected:
        bool m_bExcuted;
    };

    //一对相反的操作
    class COpertaionPair
    {
    public:
        COpertaionPair(IBaseOperation *do_, IBaseOperation *undo_);
        ~COpertaionPair();

        //回滚本操作,即本操作执行前的状态。
        bool Rollback(void);
        //执行本操作
        bool Excute(void);

        //本操作是否已执行
        bool IsExcuted(void){return m_bExcuted;};

    private:
        IBaseOperation *m_do;
        IBaseOperation *m_undo;

        bool m_bExcuted;    //true, 已执行;false, 处于回滚后的状态。
    };

    BaseOperation.cpp

    #include "BaseOperation.h"
    #include <stdlib.h>
    #include <assert.h>

    IBaseOperation::IBaseOperation(void):
    m_bExcuted(false)
    {
    }

    IBaseOperation::~IBaseOperation(void)
    {
    }

    void IBaseOperation::SetStatus(bool bExcuted_)
    {
        m_bExcuted = bExcuted_;
    }

    COpertaionPair::COpertaionPair(IBaseOperation *do_, IBaseOperation *undo_):
    m_do(do_),
    m_undo(undo_),
    m_bExcuted(false)
    {

    }

    COpertaionPair::~COpertaionPair()
    {

    }

    bool COpertaionPair::Rollback(void)
    {
        assert(m_undo != NULL);
        if(!m_bExcuted)
            return false;

        m_bExcuted = false;

    /*
        return m_undo->Excute();
    */
        bool ret = m_undo->Excute();
        if(ret)
        {
            m_undo->SetStatus(true);
            m_do->SetStatus(false);
        }

        return ret;
    }

    bool COpertaionPair::Excute(void)
    {
        assert(m_do != NULL);
        if(m_bExcuted)
            return false;

        m_bExcuted  = true;
    /*
        return m_do->Excute();
    */

        bool ret = m_do->Excute();
        if(ret)
        {
            m_do->SetStatus(true);
            m_undo->SetStatus(false);
        }

        return ret;
    }

    RecoveryManager.h

    /*----------------------------------------------------------
    desc    : 恢复功能(undo redo)模块。
    author    : zilong
    version    : 1.0
    date    : 2011-03-23

    revision:

    ----------------------------------------------------------*/

    #pragma once

    #include <stack>

    class COpertaionPair;

    class CRecoveryManager
    {
    private:
        typedef std::stack<COpertaionPair *> TOperations;

    public:
        CRecoveryManager(void);
        ~CRecoveryManager(void);

        //清空库
        void Clear(void);

        //是否可以回滚
        bool CanRollback(void);
        //是否可以向前滚动
        bool CanRoll(void);

        //执行一个操作,成功之后将该操作入库。
        bool Excute(COpertaionPair *operation_);
        //回滚一个操作。
        bool Rollback(void);
        //向前滚动一个操作。
        bool Roll(void);
        bool Rollback(int count_);
        bool Roll(int count_);

    private:
        void ClearOpertaions(TOperations &_ops_);

    private:
        TOperations m_undoes;    //
        TOperations m_redoes;
    };

    RecoveryManager.cpp

    #include "RecoveryManager.h"
    #include "rollback\BaseOperation.h"
    #include <assert.h>

    CRecoveryManager::CRecoveryManager(void)
    {
    }

    CRecoveryManager::~CRecoveryManager(void)
    {
        Clear();
    }

    void CRecoveryManager::Clear(void)
    {
        ClearOpertaions(m_redoes);
        ClearOpertaions(m_undoes);
    }

    void CRecoveryManager::ClearOpertaions(TOperations &_ops_)
    {
        while(!_ops_.empty())
        {
            delete _ops_.top();
            _ops_.pop();
        }
    }

    bool CRecoveryManager::CanRollback(void)
    {
        return !m_undoes.empty();
    }

    bool CRecoveryManager::CanRoll(void)
    {
        return !m_redoes.empty();
    }

    bool CRecoveryManager::Excute(COpertaionPair *operation_)
    {
        assert(operation_ != NULL);
        if(NULL == operation_)
            return false;

        if(operation_->Excute())
        {
            ClearOpertaions(m_redoes);
            m_undoes.push(operation_);

            return true;
        }

        return false;
    }

    bool CRecoveryManager::Rollback(void)
    {
        if(!CanRollback())
            return false;

        COpertaionPair *op = m_undoes.top();
        assert(op != NULL);
        if(op->Rollback())
        {
            m_undoes.pop();
            m_redoes.push(op);

            return true;
        }

        return false;
    }

    bool CRecoveryManager::Roll(void)
    {
        if(!CanRoll())
            return false;

        COpertaionPair *op = m_redoes.top();
        assert(op != NULL);
        if(op->Excute())
        {
            m_redoes.pop();
            m_undoes.push(op);

            return true;
        }

        return false;
    }

    举个例子。例如,要写一个文本编辑器, 其中要实现一个删除操作, 且可以实现undo, redo.
    class CDeleteTextOper: public IBaseOperation
    {
    public:
        CDeleteTextOper(CTextDataMgr *receiver);
        virtual ~CDeleteTextOper(void);

        virtual bool Excute(void)
        {
            m_pReceiver->DeleteText(m_head, m_tail);
        }

        void SetData(int head, int tail);

    protected:
        CTextDataMgr *m_pReceiver;
        int m_head;
        int m_tail;
    };

    class CAddTextOper: public IBaseOperation
    {
    public:
        CAddTextOper(CTextDataMgr *receiver);
        virtual ~CAddTextOper(void);

        virtual bool Excute(void)
        {
            m_pReceiver->AddText(m_offset, txt);
        }

        void SetData(int offset, const std::string &txt);

    protected:
        CTextDataMgr *m_pReceiver;
        int m_offset;
        std::string txt;
    };

    class CTextDataMgr
    {
    private:
        CRecoveryManager m_opManager;
    public:
        std::string GetText(int head, int tail);

    public:
        bool AddText(int offset, const std::string &txt);
        bool DeleteText(int head, int tail);

    public:
        bool DoDeleteText(int head, int tail)
        {
            CDeleteTextOper *mydo = new CDeleteTextOper(this);
            mydo->SetData(head, tail);

            CAddTextOper *undo = new CAddTextOper(this);
            undo->SetData(head, this->GetText(head, tail));

            COpertaionPair *op = new COpertaionPair(mydo, undo);
            return m_opManager.Excute(op);
        }

    public:
        virtual void Redo(void)
        {
            m_opManager.Roll();
        }

        virtual void Undo(void)
        {
            m_opManager.Rollback();
        }

        virtual bool CanRedo(void);
        virtual bool CanUndo(void);
    };

    客户端调用代码如下

    void main()
    {
        CTextDataMgr dataMgr;

        //……

        //执行操作
        dataMgr.DoDeleteText(10, 20);

        //undo
        dataMgr.Undo();

        //redo
        dataMgr.Redo();
    }

  • 相关阅读:
    《区块链100问》第56集:权益证明机制是什么?
    《区块链100问》第57集:股份授权证明机制是什么?
    《区块链100问》第58集:零知识证明是什么?
    《区块链100问》第59集:哈希算法是什么?
    《区块链100问》第60集:非对称加密算法是什么?
    《区块链100问》第61集:扩容是什么?
    《区块链100问》第62集:比特币为什么要扩容?
    《区块链100问》第63集:隔离见证是什么?
    使用Nginx后如何在web应用中获取用户ip及原理解释
    MySQL的进程状态
  • 原文地址:https://www.cnblogs.com/zilongblog/p/2760176.html
Copyright © 2020-2023  润新知