撤销和重做(Undo和Redo)的C++完美实现(8-A)

#if 0

在上一章里面已经成功的封装了复合类型,基本上已经具备了应用的基础。在这一章
里面将会尝试对前面讨论的简单类型和复合类型进行应用,同时也是进一步的进行封装的
过程。通过提供一个统一的应用界面就可以使客户端不必区别处理简单类型和复合类型之
间的各个操作的不同,而是由库来处理这种不同,这正是体现C++自动化(模板元)编程的
优势的时候了。在这一章中将会讨论这个封装过程。

#endif
#ifdef CONTROL_H
#include "center.h"
#include "identifier.h"
#include "meta.h"
#include "compound.h"
namespace pandaxcl{
//下面是简单类型和复合类型的分隔符,引入这个分隔符的目的是为了能够
//让control自动区别简单类型和复合类型,在这个分隔符之前的都是简单
//类型,在这个分隔符之后的全部是复合类型。这是该库的编码规范。
struct separator{};
//对容器类基元进行自动化包装
template <class T> struct control_unit
:public container<identifier<T>,T>
{
};
//下面是控制面板的自动化实现
template <class Cons>struct control
:public center
,public scatter<Cons,control_unit>
{
typedef Cons cons_type;
//用来判断所给的类型是简单类型还是复合类型的特性模板类
template<class T> struct traits
{
enum{
is_simple = /
static_cast<int>(index<cons_type,T>::value) /
< /
static_cast<int>(index<cons_type,separator>::value),
is_compound = /
static_cast<int>(index<cons_type,T>::value) /
> /
static_cast<int>(index<cons_type,separator>::value),
};
};
//给一种统一的接口来实现简单对象和复合对象的三种基本操作
template <class T>
identifier<T> create(const T&OC)
{
//准备好创建参数
typename CREATE<T>::ENVIRONMENT e(*this,OC);
//根据当前类型是简单类型还是复合类型选择不同的创建操作
return IF<traits<T>::is_simple,
typename CREATE<T>::Simple,
typename CREATE<T>::Compound
>::result::execute(e);
}
//当IDT为简单类型标识号时,T表示简单类
//当IDT为复合类型标识号时,T表示复合类的属性类型
//复合类型自身保存在标识号类里面
//template <int i=0,class IDT,class T>
//template <class IDT,class T,int i=0>
template <int i,class IDT,class T>
void modify(const IDT&ID,const T&OM)
{
typedef typename IDT::object_type object_type;
//准备好创建参数
typename MODIFY<object_type,i>/
::template ENVIRONMENT<T> e(*this,ID,OM);
//根据当前类型是简单类型还是复合类型选择不同的修改操作
pandaxcl::IF<traits<object_type>::is_simple,
typename MODIFY<object_type,i>::Simple,
typename MODIFY<object_type,i>::Compound
>::result::execute(e);
}
template <class IDT>
void remove(const IDT&ID)
{
typedef typename IDT::object_type object_type;
//准备好创建参数
typename REMOVE<IDT>::ENVIRONMENT e(*this,ID);
//根据当前类型是简单类型还是复合类型选择不同的修改操作
pandaxcl::IF<traits<object_type>::is_simple,
typename REMOVE<IDT>::Simple,
typename REMOVE<IDT>::Compound
>::result::execute(e);
}
private:
//针对简单类型和复合类型分别调用的创建过程
template <class T> struct CREATE
{
typedef T object_type;
typedef identifier<T> identifier_type;
typedef container<identifier<T>,T> container_type;
//传递给创建操作的环境变量
struct ENVIRONMENT
{
ENVIRONMENT(control&C,const object_type&O)
:_C(C),_O(O){}
control&_C;
const object_type &_O;
};
struct Simple
{//用来创建简单类对象
template <class EnvironmentType>
static identifier_type execute(EnvironmentType&e)
{
typedef pandaxcl::create<container_type> COMMAND;
identifier_type ID(true);
e._C.execute(new COMMAND(e._C,ID,e._O));
return ID;
}
};
struct Compound
{//用来创建复合类对象
template <class EnvironmentType>
static identifier_type execute(EnvironmentType&e)
{
identifier_type ID(true);
object_type::create(e._C,ID,e._O);
return ID;
}
};
};
//下面的模板参数size_t对于简单对象是没有用的,随便给一个整数都可以,
//但是这个模板参数对复合类型表示的就是复合类型的第i个属性类型了。
template <class T,size_t i> struct MODIFY
{
typedef T object_type;
typedef identifier<T> identifier_type;
typedef container<identifier<T>,T> container_type;
//传递给修改操作的环境变量
template <class PropertyType>
struct ENVIRONMENT
{
ENVIRONMENT(control&C,const identifier_type&ID,const PropertyType&O)
:_C(C),_ID(ID),_O(O){}
control&_C;
const identifier_type&_ID;
const PropertyType &_O;
};
struct Simple
{//用来修改简单类对象
template <class EnvironmentType>
static void execute(EnvironmentType&e)
{
typedef pandaxcl::modify<container_type> COMMAND;
e._C.execute(new COMMAND(e._C,e._ID,e._O));
}
};
struct Compound
{//用来修改复合类对象的一个属性
template <class EnvironmentType>
static void execute(EnvironmentType&e)
{
object_type::template modify<i>(e._C,e._ID,e._O);
}
};
};
//根据类型是简单类型还是复合类型调用删除操作
template <class IDT> struct REMOVE
{
typedef typename IDT::object_type object_type;
typedef IDT identifier_type;
typedef container<IDT,object_type> container_type;
//传递给删除操作的环境变量
struct ENVIRONMENT
{
ENVIRONMENT(control&C,const identifier_type&ID)
:_C(C),_ID(ID){}
control&_C;
const identifier_type &_ID;
};
struct Simple
{//用来删除简单类对象
template <class EnvironmentType>
static void execute(EnvironmentType&e)
{
typedef pandaxcl::remove<container_type> COMMAND;
e._C.execute(new COMMAND(e._C,e._ID));
}
};
struct Compound
{//用来删除复合类对象
template <class EnvironmentType>
static void execute(EnvironmentType&e)
{
object_type::remove(e._C,e._ID);
}
};
};

};
}//namespace pandaxcl{
#endif//CONTROL_H
#if 0

下面的CODE1是上面的自动化控制面板类的测试代码。在下面的代码中我们将考虑到
前面所有的章节中的内容,因此将会考虑到简单对象和复合对象同时出现,以及简单的
序列化。

#endif
#ifdef CODE1
#include <iostream>
#include "compound.h"
namespace xcl = pandaxcl;//名字空间重命名
//矩形类
class Rectangle
{
public:
Rectangle():_x(0),_y(0),_width(20),_height(10){}
Rectangle(int x,int y,int w,int h):_x(x),_y(y),_width(w),_height(h){}
private:
int _x,_y,_width,_height;
//下面的函数仅仅是为了输出信息而准备的
friend std::ostream&operator<<(std::ostream&s,Rectangle&o)
{
s << "(" << o._x << "," << o._y << "," << o._width << "," << o._height << ")" ;
return s;
}
};
//圆形类
class Circle
{
public:
Circle():_x(0),_y(0),_radius(20){}
Circle(int x,int y,int r):_x(x),_y(y),_radius(r){}
private:
int _x,_y,_radius;
//下面的函数仅仅是为了输出信息而准备的
friend std::ostream&operator<<(std::ostream&s,Circle&o)
{
s << "(" << o._x << "," << o._y << "," << o._radius << ")" ;
return s;
}
};
//圆角矩形类
typedef xcl::cons<Rectangle,
xcl::cons<Circle,//重复类型
xcl::cons<Circle,//重复类型
xcl::cons<Circle,//重复类型
xcl::cons<Circle,//重复类型
xcl::null_type> > > > >ROUNDRECTANGLE;
//由上面的类型串自动生成圆角矩形类
//typedef xcl::compound<ROUNDRECTANGLE> RoundRectangle;
class RoundRectangle : public xcl::compound<ROUNDRECTANGLE>
{
friend std::ostream&operator<<(std::ostream&s,RoundRectangle&o)
{
s << "R:[" << std::hex << xcl::field<0>(o).ID << "] " ;
s << "C:[" << std::hex << xcl::field<1>(o).ID << "] " ;
s << "C:[" << std::hex << xcl::field<2>(o).ID << "] " ;
s << "C:[" << std::hex << xcl::field<3>(o).ID << "] " ;
s << "C:[" << std::hex << xcl::field<4>(o).ID << "] " ;
return s;
}
};
//观察容器的内容而准备的
template <class Container>
void display(const char*str,Container&c)
{
typedef typename Container::value_type value_type;
struct X
{
static void print(value_type&v)
{
std::cout.setf(std::ios::showbase);//显示16进制的0x前缀
std::cout << "(" <<std::hex<< v.first << "," ;
std::cout << std::dec << v.second << ") ";
}
};
//输出提示信息,并输出容器中的元素数量
std::cout << str << "[" << std::dec << c.size() << "] ";
std::for_each(c.begin(),c.end(),X::print);//输出容器中的所有的标识号和对象信息
std::cout << std::endl;
}
//控制面板里面不应该有重复的类型,这是必须保证的:)
typedef xcl::cons<Rectangle,
xcl::cons<Circle,
xcl::cons<xcl::separator,//简单对象和复合对象的分界线
xcl::cons<RoundRectangle,
xcl::null_type> > > > CONTROL;
class Control : public xcl::control<CONTROL>
{
public:
//下面的函数是输出该控制面板对象的相关信息的
void display(const char*str)
{
std::cout << "----------"<<str<<"----------" <<std::endl;
std::cout << "Undo:[" << std::dec << xcl::center::undo_type::size() << "] " ;
std::cout << "Redo:[" << std::dec << xcl::center::redo_type::size() << "] " ;
std::cout << std::endl ;
//::display("矩形容器 :",xcl::field<0>(*this));
//::display("圆形容器 :",xcl::field<1>(*this));
//::display("圆角矩形容器:",xcl::field<2>(*this));
//正是因为控制面板里面没有重复的类型,所以可以直接使用下面的
//field函数
::display("矩形容器 :",xcl::field<Rectangle >(*this));
::display("圆形容器 :",xcl::field<Circle >(*this));
::display("圆角矩形容器:",xcl::field<RoundRectangle>(*this));
std::cout << "=========="<<str<<"==========" <<std::endl;
}
};

int main()
{
//首先应用程序中必须有一个全局的控制面板类对象
Control C;
//复合对象的标识号对象,这里采用false参数表示不产生新标识号
xcl::identifier<Rectangle> idr (false);
xcl::identifier<Circle> idc (false);
xcl::identifier<RoundRectangle> idcom(false);
//模拟创建对象
C.record();
idr = C.create(Rectangle() );
idc = C.create(Circle() );
idcom = C.create(RoundRectangle());
C.stop();
C.display("创建对象");
C.undo();//撤销一步
C.display("撤销一步");
C.redo();//重做一步
C.display("重做一步");
//模拟修改对象
C.record();
//C.modify(idr ,Rectangle(11,22,1000,2000));
//C.modify(idc ,Circle (11,22,1000 ));
//修改简单对象的时候任意给出一个模板参数就可以啦
C.modify<0>(idr ,Rectangle(11,22,1000,2000));
C.modify<0>(idc ,Circle (11,22,1000 ));
C.modify<0>(idcom,Rectangle(1 ,1 ,200,100));
C.modify<1>(idcom,Circle (1 ,1 ,5 ));
C.modify<2>(idcom,Circle (201,1 ,5 ));
C.modify<3>(idcom,Circle (201,101,5 ));
C.modify<4>(idcom,Circle (1 ,101,5 ));
C.stop();
C.display("修改对象");
C.undo();//撤销一步
C.display("撤销一步");
C.redo();//重做一步
C.display("重做一步");
//模拟删除复合对象
C.record();
C.remove(idr );
C.remove(idc );
C.remove(idcom);
C.stop();
C.display("删除对象");
C.undo();//撤销一步
C.display("撤销一步");
C.redo();//重做一步
C.display("重做一步");
return 0;
}
#endif//CODE1

//该程序的运行结果:
/*******************************************************************************
----------创建对象----------
Undo:[1] Redo:[0]
矩形容器 :[2] (0x1,(0,0,20,10)) (0x2,(0,0,20,10))
圆形容器 :[5] (0x1,(0,0,20)) (0x2,(0,0,20)) (0x3,(0,0,20)) (0x4,(0,0,20)) (0x5,(0,0,20))
圆角矩形容器:[1] (0x1,R:[0x2] C:[0x2] C:[0x3] C:[0x4] C:[0x5] )
==========创建对象==========
----------撤销一步----------
Undo:[0] Redo:[1]
矩形容器 :[0]
圆形容器 :[0]
圆角矩形容器:[0]
==========撤销一步==========
----------重做一步----------
Undo:[1] Redo:[0]
矩形容器 :[2] (0x1,(0,0,20,10)) (0x2,(0,0,20,10))
圆形容器 :[5] (0x1,(0,0,20)) (0x2,(0,0,20)) (0x3,(0,0,20)) (0x4,(0,0,20)) (0x5,(0,0,20))
圆角矩形容器:[1] (0x1,R:[0x2] C:[0x2] C:[0x3] C:[0x4] C:[0x5] )
==========重做一步==========
----------修改对象----------
Undo:[2] Redo:[0]
矩形容器 :[2] (0x1,(11,22,1000,2000)) (0x2,(1,1,200,100))
圆形容器 :[5] (0x1,(11,22,1000)) (0x2,(1,1,5)) (0x3,(201,1,5)) (0x4,(201,101,5)) (0x5,(1,101,5))
圆角矩形容器:[1] (0x1,R:[0x2] C:[0x2] C:[0x3] C:[0x4] C:[0x5] )
==========修改对象==========
----------撤销一步----------
Undo:[1] Redo:[1]
矩形容器 :[2] (0x1,(0,0,20,10)) (0x2,(0,0,20,10))
圆形容器 :[5] (0x1,(0,0,20)) (0x2,(0,0,20)) (0x3,(0,0,20)) (0x4,(0,0,20)) (0x5,(0,0,20))
圆角矩形容器:[1] (0x1,R:[0x2] C:[0x2] C:[0x3] C:[0x4] C:[0x5] )
==========撤销一步==========
----------重做一步----------
Undo:[2] Redo:[0]
矩形容器 :[2] (0x1,(11,22,1000,2000)) (0x2,(1,1,200,100))
圆形容器 :[5] (0x1,(11,22,1000)) (0x2,(1,1,5)) (0x3,(201,1,5)) (0x4,(201,101,5)) (0x5,(1,101,5))
圆角矩形容器:[1] (0x1,R:[0x2] C:[0x2] C:[0x3] C:[0x4] C:[0x5] )
==========重做一步==========
----------删除对象----------
Undo:[3] Redo:[0]
矩形容器 :[0]
圆形容器 :[0]
圆角矩形容器:[0]
==========删除对象==========
----------撤销一步----------
Undo:[2] Redo:[1]
矩形容器 :[2] (0x1,(11,22,1000,2000)) (0x2,(1,1,200,100))
圆形容器 :[5] (0x1,(11,22,1000)) (0x2,(1,1,5)) (0x3,(201,1,5)) (0x4,(201,101,5)) (0x5,(1,101,5))
圆角矩形容器:[1] (0x1,R:[0x2] C:[0x2] C:[0x3] C:[0x4] C:[0x5] )
==========撤销一步==========
----------重做一步----------
Undo:[3] Redo:[0]
矩形容器 :[0]
圆形容器 :[0]
圆角矩形容器:[0]
==========重做一步==========
*******************************************************************************/


#if 0

从上面的讨论可以看出,我们已经成功的封装了简单类型和复合类型的三个基本操作
,给出了一个统一的调用接口。这样客户端就只需要按照这个简单的格式来操作对象就可
以了。当然这里还有一个假设:那就是所有的客户端类型只有两种:简单类型和复合类型
。实际上只要这两种类型就可以生成无数的具体类型了,而且表达能力也非常强,对于一
般的应用已经足够了。值得说明的是,使用这个撤销和重做库编写代码的过程在很大的程
度是编写思想的过程。代码中蕴涵了大量的设计思想,这一点就非常重要,在进行软件维
护的时候就可以看出这种优势了。为了以后讨论的方便,我将把这一章里面的CONTROL_H之
间的代码保存到“control.h”文件中,方便以后讨论。

虽然有了这些基本操作可以实现其它的一切可撤销操作,但是仍然有些不方便,例如
:选择一个独立的矩形对象的操作就需要编写大量的代码(独立的矩形对象就是不是某个
复合对象的一个属性的矩形对象)。所以为了方便客户端编写这种代码,必须给出一种规
范,同时为了尽可能的利用STL的算法,在下一章里面将会讨论如何利用STL算法来实现自
己需要的特殊功能。(敬请关注!)

未完,待续...

#endif
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值