命令模式Command¶
概念¶
Command模式通过被称为Command的类封装了对目标对象的调用行为以及调用参数。
YTKNetwork行为参数化,降低代码重合度。
在面向对象的程序设计中,一个对象调用另一个对象,一般情况下的调用过程是:创建目标对象实例、设置调用参数、调用目标对象的方法。
但在有些情况下有必要使用一个专门的类对这种调用过程加以封装,我们把这种专门的类称作command类。
一个对象调用另一个对象一般情况下是直接new该对象然后调用对象的方法,命令模式就是设计一个command类去调用这个对象 。
整个调用过程比较繁杂,或者存在多处这种调用。这时,使用Command类对该调用加以封装,便于功能的再利用。
调用前后需要对调用参数进行某些处理。调用前后需要进行某些额外处理,比如日志,缓存,记录历史操作等。
角色和职责¶
- Command Command命令的抽象类。
- ConcreteCommand Command的具体实现类。
- Receiver 需要被调用的目标对象。
- Invorker 通过Invorker执行Command对象。
医生功能比较多的时候 看各种病 通过命令就把医生分解了,通过每一种命令看每一种病。
医生越来越牛 功能越来越多,病人也越来越多的时候,就需要排队。也就是把一个一个客户端请求队列化集合化。
Receiver就是医生。
Invorker就相当于一个小护士,把所有的请求都收集起来,然后让医生一个一个的看病,一个一个的处理。
Invorker-持有Command
Invorker的好处就是,客户端可以面向命令进行编程,Invorker调用不同的命令,对命令进行解耦合。
适用于¶
是将一个请求封装为一个对象,从而可用不同的请求对客户端进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。
命令模式是一种对象行为型模式,其别名为动作(Action)模式或事务(Transaction)模式。
对象的调用,使用一个command类去调用。
例¶
医生看病:医生可以看各种各样的病:可以看眼科 可以看鼻科 等等。
- 一般情况下 医生直接看病 直接使用医生去看病
直接new一个医生然后调用看眼科 看耳科。这种情况下客户端和医生的耦合度太高了,如果医生生病了就没法看病了。
- 通过命令。
做不同的命令 把医生注入到命令类里面 调用的时候 通过不同的命令来看不同的病。
看眼病命令类持有一个医生对象,调用医生的看眼病函数去看眼病。
看耳病命令类持有一个医生对象,调用医生的看耳病函数去看耳病。
病人多了 不同命令类 调用医生去看病
护士下命令 让医生去看病
高级用法¶
批量下单
护士长 可以收集多个命令,有一个命令list集合 一组命令 然后去调用
添加看眼科命令,添加看耳科命令。批量处理。
可以添加命令到list中 提交病历,批量下达命令,让医生执行。效率更高。
例:
#include <iostream>
using namespace std;
#include "list"
class Doctor
{
public:
void treat_eye()
{
cout << "医生 治疗 眼科病" << endl;
}
void treat_nose()
{
cout << "医生 治疗 鼻科病" << endl;
}
};
class Command
{
public:
virtual void treat() = 0;
};
class CommandTreatEye : public Command
{
public:
CommandTreatEye(Doctor *doctor)
{
m_doctor = doctor;
}
void treat()
{
m_doctor->treat_eye();
}
private:
Doctor *m_doctor;
};
class CommandTreatNose : public Command
{
public:
CommandTreatNose(Doctor *doctor)
{
m_doctor = doctor;
}
void treat()
{
m_doctor->treat_nose();
}
private:
Doctor *m_doctor;
};
class BeautyNurse
{
public:
BeautyNurse(Command *command)
{
this->command = command;
}
public:
void SubmittedCase() //提交病例 下单命令
{
command->treat();
}
protected:
private:
Command *command;
};
//护士长
class HeadNurse
{
public:
HeadNurse()
{
m_list.clear();
}
public:
void setCommand(Command *command)
{
m_list.push_back(command);
}
void SubmittedCase() //提交病例 下单命令
{
for (list<Command *>::iterator it=m_list.begin(); it!=m_list.end(); it++)
{
(*it)->treat();
}
}
private:
list<Command *> m_list;
};
void main21_1()
{
//1 医生直接看病
/*
Doctor *doctor = new Doctor ;
doctor->treat_eye();
delete doctor;
*/
//2 通过一个命令 医生通过 命令 治疗 治病
Doctor *doctor = new Doctor ;
Command * command = new CommandTreatEye(doctor); //shift +u //转小写 shift+ctl + u转大写
command->treat();
delete command;
delete doctor;
return ;
}
void main21_2()
{
//3 护士提交简历 给以上看病
BeautyNurse *beautynurse = NULL;
Doctor *doctor = NULL;
Command *command = NULL;
doctor = new Doctor ;
//command = new CommandTreatEye(doctor); //shift +u //转小写 shift+ctl + u转大写
command = new CommandTreatNose(doctor); //shift +u //转小写 shift+ctl + u转大写
beautynurse = new BeautyNurse(command);
beautynurse->SubmittedCase();
delete doctor;
delete command;
delete beautynurse;
return ;
}
//4 通过护士长 批量的下单命令
void main21_3()
{
//护士提交简历 给以上看病
HeadNurse *headnurse = NULL;
Doctor *doctor = NULL;
Command *command1 = NULL;
Command *command2 = NULL;
doctor = new Doctor ;
command1 = new CommandTreatEye(doctor); //shift +u //转小写 shift+ctl + u转大写
command2 = new CommandTreatNose(doctor); //shift +u //转小写 shift+ctl + u转大写
headnurse = new HeadNurse(); //new 护士长
headnurse->setCommand(command1);
headnurse->setCommand(command2);
headnurse->SubmittedCase(); // 护士长 批量下单命令
delete doctor;
delete command1;
delete command2;
delete headnurse;
return ;
}
void main()
{
//main21_1();
//main21_2();
main21_3();
cout<<"hello..."<<endl;
system("pause");
return ;
}
总结¶
命令模式就是 把一个功能很多很强大的类 分成很多小命令来使用。
医生多才多艺,会看各种病,把看每一种病通过做对应的一个命令来调用。主要是解耦合。
命令模式把动作进行分解,分解成一个发起者,真正执行动作的人。
医生可以看很多病,还可以有各种医生。
命令模式的优点¶
- 降低系统的耦合度。
- 新的命令可以很容易地加入到系统中。
- 可以比较容易地设计一个命令队列和宏命令(组合命令)。
- 可以方便地实现对请求的Undo和Redo。