C++行为型模式-实现命令者模式

1.1 命令模式定义

        命令者模式将请求的发送者与接收者解耦,在发送者与接受者之间引入命令对象,将发送者的请求封装在命令对象中,在通过命令对象来调用接收者的方法。

        命令模式(Command Pattern):将一个请求封装为一个对象,从而使我们可以用不同的请求对客户进行参数化,对请求排列或记录请求日志,以及支持可撤销的操作,命令模式是一种对象行为模式。

1.2 命令者模式结构

命令者模式包括请求的发送者、接受者、抽象命令、具体命令等角色。 

(1)Command(抽象命令类)

抽象命令类一般是一个接口,在其中声明了用于执行请求的execute()等方法,通过这些方法可以调用请求接收者的相关操作。

command实现请求调用者和接受者解耦。

(2)ConcreteCommand(具体命令类)

具体命令类是抽象命令类的子类,实现抽象命令类的子类,在实现execute()方法时,将调用接受者对象的相关操作(action)

(3)Invoker(调用者)

调用者即请求的发送者,它通过命令对象来执行请求,一个调用者并不需要在设计时确定其接受者,因此它只与抽象命令类之间存在关联关系

(4)Receiver(接受者)

接受者执行与请求相关的操作,它具体实现对请求业务处理。

(5)Client(客户类)

在客户端类中需要创建发送者对象和具体命令类对象,在创建具体命令对象时指定其对应的接受者,发送者和接受者之间无直接关系,通过具体命令对象实现间接调用。

1.3 优缺点

命令者模式允许请求的一方与接收一方独立开来,使得请求的一方不必知道接收请求的一方的接口,使得请求的一方不必知道接收请求的一方的接口,更不必知道请求是怎么被接收、操作是否被执行,以及是怎么被执行。

优点:

(1)降低系统的耦合度。请求者和接受者直接不存在直接引用,相同的请求者可以对应不同的接收者,相同的接受者也可供不同的请求者使用。

(2)新的命令可以很容易地加入系统中。增加的新的具体命令不影响其他的类,因此增加新的具体命令类很容易,无需修改原有系统原代码,满足“开闭原则”。

缺点:

导致某些系统使用过多的具体命令类。

1.4 应用场景

        命令模式的本质是对命令进行封装,将发出命令的责任和执行命令的责任分隔开。

        每一个命令都是一个操作,请求的一方发出请求,要求执行一个操作;接收的一方收到请求,并执行操作。请求的一方不必知道接受请求的一方的接口,更不必知道请求是怎么被接收、操作是否被执行、何时被执行,以及是怎么被执行的。

        命令模式使得请求本身成为一个对象,这个对象和其他对象一样可以被存储和传递。

(1)系统需要将请求的调用者和请求接受者解耦,使得调用者和接受者不直接交互。

(2)系统需要在不同的时间指定请求、将请求排队和执行请求;

(3)系统需要支持命令的撤销(undo)操作和恢复(redo)操作。

1.5 代码实现

应用:电视机是请求的接受者,遥控器是请求的发送者,遥控器上有一些按钮,不同的按钮对应电视机的不同操作,抽象命令者有一个命令接口,三个具体的命令类实现抽象命令接口,分别打开电视、关闭电视和切换频道。

 

#include <iostream>
#include <list>
using namespace std;

#define SAFE_DELETE(p) if (p) { delete p; p = NULL; }

// Televisonr类(请求接收者),知道如何实施与执行一个与请求相关的操作:
class Televison {
public:
    void open() {
        cout << "open the  televison" << endl;
    }
	void close() {
        cout << "close the  televison" << endl;
    }
	void changeChannel() {
        cout << "changeChannel the  televison" << endl;
    }
};

// Command类(抽象命令类),用来声明执行操作的接口
class Command {
public:
    virtual void excute() = 0;
    virtual void setReceiver(Televison* tv) = 0;
    virtual ~Command(){};
};

// TVOpenCommand类(具体命令类),绑定一个Receiver,调用其相应操作以实现Excute:
class TVOpenCommand : public Command {
private:
    Televison* tv_;
public:
    void setReceiver(Televison* tv) {
    	tv_ = tv;
    }
    void excute() {
        tv_->open();//调用接受者请求响应方法
    }
};

// TVCloseCommand类(具体命令类),绑定一个Receiver,调用其相应操作以实现Excute:
class TVCloseCommand : public Command {
private:
    Televison* tv_;
public:
    void setReceiver(Televison* tv) {
    	tv_ = tv;
    }
    void excute() {
        tv_->close();//调用接受者请求响应方法
    }
};

// TVCloseCommand类(具体命令类),绑定一个Receiver,调用其相应操作以实现Excute:
class TVChangeCommand : public Command {
private:
    Televison* tv_;
public:
    void setReceiver(Televison* tv) {
    	tv_ = tv;
    }
    void excute() {
        tv_->changeChannel();//调用接受者请求响应方法
    }
};

// 调用者类Controller(遥控器类),请求发送者Invoker,要求该命令执行这个请求:
class Controller {
private:
    list<Command* > commands;
public:
    void setCommand(Command* c) {//通过构造函数注入或设置注入的方式运行时传入具体命令类对象
        commands.push_back(c);
    }
    void notify() {
        for (auto c = commands.begin(); c != commands.end(); c++) {
            (*c)->excute();//调用excute()
        }
    }
};

// 客户端实现代码:
int main() {
    Command* openCommand = new TVOpenCommand();
	Command* changeCommand = new TVChangeCommand();
	Command* closeCommand = new TVCloseCommand();
    Televison *televison = new Televison();
    openCommand->setReceiver(televison);//第一步:请求接受者作为构造函数的参数来创建具体的command对象

    Controller *controller = new Controller();
    controller->setCommand(openCommand);//第二步:将具体Command对象保存在请求调用者中
    controller->notify();   // 第三步请求调用者调用Command对象的excute()方法,后者再调用请求接受者的action()方法完成对请求的处理

    SAFE_DELETE(openCommand);
	SAFE_DELETE(changeCommand);
	SAFE_DELETE(closeCommand);
	SAFE_DELETE(televison);
	SAFE_DELETE(controller);
    return 0;
}

执行结果:

open the  televison

参考文献:

【】命令模式C++实现:设计模式--命令模式C++实现 - 狼行博客园 - 博客园

【2】C++设计模式——命令模式 CommandC++设计模式——命令模式 Command - 王陸 - 博客园

【3】C++ 在线工具 | 菜鸟工具C++ 在线工具 | 菜鸟工具

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值