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();
}