命令模式
面向对象中,一实例化一个对象,然后填充该对象。再由别的对象调用该对象。
将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化。单个请求封装成对象以后,我们就可以对这个请求存储更多的信息,使请求拥有更多的能力。
将请求封装为对象,那么可以不必为用户的每一次提交请求都去执行,只要当前客户已经提交过请求,那么就忽略或提示消息给用户。
同时用户可以撤销请求(或者可不可以更改请求内容?)
然后服务器将请求排队,然后处理。
实现
那12306网站来说。
命令可能有很多种,比如订票命令,退票命令,改签命令等等,等等乱七八糟的。
如果能一起接收这些命令,那么就需要一个抽象层,命令继承一个基类。这样接收这个基类的指针就可以了。
所以命令类应该有两个。
UML
命令类
封装请求和处理请求的对象。并不直接去处理这些请求。
所以他实际的成员函数都可以的protect,因为这些对象的成员函数都是有提交这些请求的对象来处理。
这些类都应该持有一个处理这些请求的对象,所以我们在基类中指定有这么一个私有成员,在初始化的时候填充。
然后每一个具体的命令类,都应该有自己的一些数据成员,比如订票的时候用户信息,票的信息等,我们存储在Data
这个集合,或者我们自己假设的一个类型中。
//抽象层
class Commend
{
public:
virtual void doit()=0;
};
//具体的命令类
class OrderCom:public Commend
{
public:
OrderCom(Hander *);
vitrual void doit()
{
hander->exc();
}
private:
Data data;
Handler *handler;
};
class RefundCom:public Commend
{
//实现,同上
private:
Handler *handler;
};
命令类与具体执行命令的类,应该应该解耦。也就是在做中间层。
这个中间层应不应该也是个虚类,然后具体的子类再执行对应的命令?
这个就要示情况而定了。
因为这里已经实现了解耦,如果对一个请求处理的对象可以有多个,那么就有必要做一个抽象层。
handle
类执行具体处理任务。
class Handle
{
}
为了实现请求的排队和集中处理,我们还需要在做一个对象。用来集中管理这些命令子类。
说白了,这些命令子类,只是在封装需要处理的对象,和处理者。它们他们并不进行实际的处理。
这个类,可以继承Commend
也可以不继承,这个类持有一个容器他存储这些Commend
,继承的原因是:这个队列类也有一个函数成员exc()
用来执行容器里面Commend
。
class Exc
{
public:
void exc();//挨个执行队列里的命令
void add();
void remove();
private:
vector<Commend *> _list;
};
除去析构,在移除Commend
时要一个个遍历,如果多的话,那就很麻烦了。
责任链模式
使多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系。将这些对象链成一条链,并沿着这条链传递该请求/命令,直到有一个对象处理了该请求。
简单来讲,就是可以将一个对象(或者是命令模式中的一个请求),传递给一条“链”,直到链中的某个处理该请求的对象,处理了个对象,那么就返回。
实现
现象一下,可以这样做:
能够传递
- 要是这个请求可以在一条链中传递,那么能想到的方法,就是将处理这个请求的对象做一个抽象层,然后每个实际的处理类继承这个抽象层。然后一个储存这个“链”的类,拥有一个容器,按照顺序存储处理类的对象。
2.节省一个“链”类,想list
一样(单向链表),将下一个处理对象存储在本对象中,如果本对象不能处理该对象,那么就调用下一个处理对象的处理函数。
确保一定能够被处理
调用处理类的成员函数,先判断是否能够处理该对象,如果不能,那就。。。跳。。。
也可以在条之前判断一下_next
如果是一个nullptr
那么就返回false
。这样的话,可以不用使用终端的那个类。
- 采用第一种容器的方式,那么就遍历对象,依次调用。如果能够处理就
break
。同时,在开始处理之前,可以确保容器的尾元素一定能够和醋里该对象。 - 采用第二种“单向链表”方式,那么需要确保最后一个处理类的成员函数一定能够处理该请求,或者就返回一个不能处理。
请求需要存储在处理类中嘛?
采用处理类调用函数成员直接处理请求,那么请求可以不用存储。
如何添加下一个处理类
可以直接采用函数成员addNext()
的方式。
也可以采用直接在构造函数中初始化。
最后,选取的是“单向链表”的方式。
UML
代码
//处理类的基类
class AbHandler
{
public:
virtual bool exc(Req * req)=0;
private:
AbHandler *_next;
};
//处理类,根据信息判断是否可以执行。
class Exc1Handler:AbHandler
{
public:
Exc1Handler(AbHandler* handler):_next(handler);
virtual bool exc(Req * req)
{
if(/*判断req信息和本类的其他数据成员是否能够处理该请求*/)
{
//do
return true;
}
return _next->exc(req);
}
};
//链的终端,确保一定可以执行。
class EndHandler:Abhandler
{
//其他不变,构造函数传入参数为空
public:
virtual bool exc()
{
//提示信息
return false;
}
};
使用
int main()
{
EndHandler *endHandler=new EndHandler;
Exc1Handler *exc1=new Exc1Handler(endHandler);
//.....添加其他的。
Exc9Handler *exc9=new Exc9Handler(exc8);
//另外一个请求类。。。
Req req;
exc9->exc(req);
}
链的终端先创建,然后执行的是链的开头。