您的位置:首页 > 其它

【设计模式学习笔记十五】【行为模式】【命令模式(Command)】

2015-01-31 22:01 543 查看
本文是学习刘伟技术博客和《设计模式-可复用面向对象软件的基础》笔记,博客链接:/article/1610242.html

主要是对博客和书本做提炼和记录,更多是对设计模式的基础框架学习,细节将略去,侧重对每个设计模式框架的理解。

我应该理解和掌握的:

1)能够画出这个设计模式的架构框图;

2)能够根据架构框图写出对应的伪代码;

3)这个模式的应用场景,主要优缺点。

1.命令模式

现实生活中,最直观的命令模式例子便是开关灯,开关是一个发送请求者,接收者是电灯泡,电线可以看做是一个命令;这便是一个命令模式的流程;发送者按下开关,它本身根本不需要知道开的是哪个电器,我们也可以把电线接到日光灯,替换原有的灯泡。所以把接有不同电器的电线接到开关,这样开关与电线连接的电器就不存在直接的耦合关系。命令模式可以将请求发送者和接收者完全解耦,发送者与接收者之间没有直接的引用关系,发送请求的对象只需要知道如何发送请求,而不必知道如何完成请求。

(1)定义

命令模式:将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。别名又称动作模式或事务模式。

1)命名模式结构图

核心在于引入了命令类,通过它来降低发送者和接收者的耦合度,请求发送者只需指定一个命令对象,再通过命令对象来调用请求接收者的处理方法。



2)参与者

a) Command(抽象命令类):声明执行操作的借口;
b) ConcreteCommand(具体命令类):将一个接收者对象绑定于一个动作;调用接收者相应的操作,以实现Execute();
c) Client(客户端):创建一个具体命令并设定他的接收者,绑定到调用者。
d) Invoker(调用者):要求该命令执行这个请求。注入的是抽象命令类,客户端程序通过嵌入不同的具体命令类即可。
e) Receiver(接收者):接收者执行与请求相关的操作,任何类都可能作为一个接收者。

3)看图写程序

/*
 ** FileName     : CommandPattern
 ** Author       : lin005
 ** Date         : 2015/02/01
 ** Description  : More information, please go to http://blog.csdn.net/amd123456789  */
//接收者
class Receive
{
public:
    void action()//接收者方法
    {
        cout<<"Receive Actioin()"<<endl;
    }
};
//抽象命令类
class Command
{
public:
    virtual void execute() = 0;//声明操作接口
};
//调用者,类似我所说的开关
class Invoker
{
public:
    Invoker(Command* command):c(command){}
    void call()
    {
        c->execute();
    }
private:
    Command* c;//注入抽象命令类,通过它来调用接收者,骑到耦合的作用
};
//具体命令对象,把它注入给调用者
class ConcreteCommand:public Command
{
public:
    ConcreteCommand(Receive* rc):r(rc){}
    void execute()
    {
        r->action();
    }
private:
    Receive* r;//注入接收者,最后调用它来执行操作。
};
//客户端编程
int main(int argc, const char * argv[]) {
    //接收者
    Receive* r = new Receive();
    //命令
    Command* c = new ConcreteCommand(r);
    //调用者
    Invoker* i = new Invoker(c);
    i->call();
    return 0;
}

4)命令队列

将多个请求排队,当一个请求发送者发送一个请求时,将不止一个请求接收者产生相应,这些请求接收者将逐个执行业务方法,完成对请求的处理。其实我的理解是,基本原理不变,对上面进行扩展而已,所以还是得通过最基本的结构图,进行扩展去理解其他的实现。

//声明一个命令队列类,存储所有具体命令对象
//调用者注入命令队列对象
class CommandQueue
{
public:
    void addCommand(Command* c)
    {
        commandList.push_back(c);
    };
    void removeCommand(Command* c)
    {
        //业务实现
    };
    void execute()
    {
        //对队列进行遍历,执行业务方法
    }
private:
    vector<Command*> commandList;
};


(2)总结

1)优点

a) 降低系统的耦合度,将调用操作的对象与知道如何实现该操作的对象解耦。
b)
增加新的Command很容易,因为无需改变已有的类。
c)
你可以将多个命令装配成一个复合命令。比如命令队列。

2)缺点

a) 针对每一个对请求接收者的调用操作都需要设计一个具体命令类,使用命令模式可能会导致过多的具体命令类。

(3)使用场景

1)系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互。
2)系统需要在不同的时刻指定、排列、执行请求。一个Command对象可以有一个和初始请求无关的生存期。
3)支持命令的撤销和恢复操作。Command的Execute操作前将状态存储起来,在取消操作时这个状态用来消除该操作的影响。Command接口必须添加一个UnExecute()操作,该操作取消上一次Execute调用的结果,执行的命令被存储在一个历史列表中,通过向前和向后遍历这一列表分别来调用Execute和UnExecute实现重数不限的取消和重做。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: