一个实现恢复删除机制(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();
}

原文地址:https://www.cnblogs.com/zilongblog/p/2760176.html