命令模式C++实现

Posted 今天也要努力搬砖

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了命令模式C++实现相关的知识,希望对你有一定的参考价值。

参考书籍《Head First设计模式》


命令模式

        命令模式-将请求封装成对象,这可以让你使用不同的请求、队列,或者日志请求来参数化对象。命令模式也可以支持撤销操作。

        命令模式将发出请求的对象和执行请求的对象解耦,请求对象和执行请求的对象是通过命令对象进行沟通的,命令对象封装了接受者和一个或一组动作。在c++中,命令对象持有一个接受者(执行请求的对象)的指针或引用,实现一个execute方法,execute方法中调用接受者的某些接口,实现具体请求命令。

命令模式类图

        图片来源【C++设计模式】命令模式_奋斗的大庆的博客-CSDN博客_c++命令模式,侵删。

        Clinent负责创建ConcreteCommand,并设置接收者。Invoker持有一个命令对象,并在某个时间点调用对象的execute方法,将请求付诸实现。Command抽象类声明了一个方法execute。调用命令对象的execute方法,就可以让接收者执行相关的动作。ConcreteCommand定义了动作和接收者之间的绑定关系。调用者只要调用execute就可以发出请求,然后由ConcreteCommand调用接收者的一个或多个动作。

        上面这段话看起来比较抽象,看下面的具体例子和代码,就比较清晰直观了。

案列描述

        遥控器有7个可编程的插槽(每个都可以指定到不同的家电装置)每个插槽都有对应得开关按钮。目前家电类包括电灯风扇热水器音响等,以后可能还会增加。案例要求是创建一组控制遥控器的API,让每个插槽都能够控制一个或一组装置。

        使用命令模式对应该案例,其中遥控器RemoteControl是调用者,家电灯Light和电视TV是接收者,我们设计一组Command,调用者和接收者完全解耦,通过command对象沟通。

代码实现

        

         声明:类的声明和实现在同一个文件里是个坏习惯,坏习惯,坏习惯,但因为我懒,还是写一起了,大家不要效仿,要引以为戒,要引以为戒,要引以为戒。

        首先定义 Light和TV类作为动作请求的接收者

        

//家电装置,receiver
class Light 
public:
	void on() 
		std::cout << "Light on!" << std::endl;
	
	void off() 
		std::cout << "Light off!" << std::endl;
	
;

class TV 
public:
	void on() 
		std::cout << "TV on!" << std::endl;
	
	void off() 
		std::cout << "TV off!" << std::endl;
	
;

        为开灯、关灯、开电视、关电视分别定义对应得ConcreteCommand类,类的构造接收一个动作执行者。

//Command类
class Command 
public:
	virtual void execute() = 0;
;

//空命令什么都不做
class VoidCommand :public Command 
public:
	VoidCommand() 
	void execute()override  
private:
	Light* mLight;
;

class LightOnCommand :public Command 
public:
	LightOnCommand(Light* light):mLight(light)
	void execute()override mLight->on(); 
private:
	Light* mLight;
;

class LightOffCommand :public Command 
public:
	LightOffCommand(Light* light) :mLight(light) 
	void execute()override  mLight->off(); 
private:
	Light* mLight;
;

class TVOnCommand :public Command 
public:
	TVOnCommand(TV* tv) : mTV(tv) 
	void execute()override  mTV->on(); 
private:
	TV* mTV;
;

class TVOffCommand :public Command 
public:
	TVOffCommand(TV* tv) : mTV(tv) 
	void execute()override  mTV->off(); 
private:
	TV* mTV;
;

        定义遥控器类,遥控器类含有两组Command对象,当按下按钮时调用对应command的execute的方法。

//调用者,遥控器类
class RemoteControl 
public:
	RemoteControl()
	
		for (int i = 0; i < 7; i++)
		
			onCommands[i] = new VoidCommand();//初始化为空命令。
			offCommands[i] = new VoidCommand();//初始化为空命令。
		
	
	~RemoteControl()
	
		for (int i = 0; i < 7; i++)
		
			delete onCommands[i];
			onCommands[i] = nullptr;
			delete offCommands[i];
			offCommands[i] = nullptr;
		
	

	
	void setCommand(int slot, Command* onCommand, Command* offCommand)
	
		delete onCommands[slot];
		onCommands[slot] = onCommand;
		delete offCommands[slot];
		offCommands[slot] = offCommand;
	

	void onButtonWasPushed(int slot)
	
		onCommands[slot]->execute();
	


	void offButtonWasPushed(int slot)
	
		offCommands[slot]->execute();
	
private:
	Command* onCommands[7];
	Command* offCommands[7];
;

        RemoteControlTest是测试类,在该类中实例化light,tv和命令对象,并把命令对象指定到遥控器的槽里面。

        

class RemoteControlTest 
public:
	void test()
	
		RemoteControl remoteControl;
		//实例化接收者对象和命令对象
		Light light;
		LightOnCommand lightOnCommand(&light);
		LightOffCommand lightOffCommand(&light);
		TV tv;
		TVOnCommand tvOnCommand(&tv);
		TVOffCommand tvOffCommand(&tv);

		remoteControl.setCommand(0, &lightOnCommand, &lightOffCommand);
		remoteControl.setCommand(1, &tvOnCommand, &tvOffCommand);
		
		remoteControl.onButtonWasPushed(0);
		remoteControl.onButtonWasPushed(1);
		remoteControl.offButtonWasPushed(0);
		remoteControl.offButtonWasPushed(1);
	
;

执行结果

 

命令模式支持可撤销操作

       要支持撤销操作,需要以下工作。

        1、Command对象提供execute()相反的undo()方法。

        在该案例中,LightOnCommand中的undo应该执行相反的动作,即off;LightOffCommand中light.undo应该执行light.on。针对TV的两个conmmand同理。

         2、需要追踪最后被调用的命令。

                在该案例中,在RemoteControl中增加一个新的Command用来追踪最后被调用的命令。

增加undo命令后的代码如下,加粗部分是针对undo功能新增加的。

// command.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>

//家电装置,receiver
class Light
public:
    void on()
        std::cout << "Light on!" << std::endl;
    
    void off()
        std::cout << "Light off!" << std::endl;
    
;

class TV
public:
    void on()
        std::cout << "TV on!" << std::endl;
    
    void off()
        std::cout << "TV off!" << std::endl;
    
;

//Command类
class Command
public:
    virtual void execute() = 0;
    virtual void undo() = 0;
;

//空命令什么都不做
class VoidCommand :public Command
public:
    VoidCommand()
    void execute()override
    void undo()override
;

class LightOnCommand :public Command
public:
    LightOnCommand(Light* light):mLight(light)
    void execute()override mLight->on();
    void undo()override mLight->off();
private:
    Light* mLight;
;

class LightOffCommand :public Command
public:
    LightOffCommand(Light* light) :mLight(light)
    void execute()override mLight->off();
    void undo()override mLight->on();
private:
    Light* mLight;
;

class TVOnCommand :public Command
public:
    TVOnCommand(TV* tv) : mTV(tv)
    void execute()override mTV->on();
    void undo()override mTV->off();
private:
    TV* mTV;
;

class TVOffCommand :public Command
public:
    TVOffCommand(TV* tv) : mTV(tv)
    void execute()override mTV->off();
    void undo()override mTV->on();
private:
    TV* mTV;
;

//调用者,遥控器类
class RemoteControl
public:
    RemoteControl()
    
        for (int i = 0; i < 7; i++)
        
            onCommands[i] = new VoidCommand();//初始化为空命令。
            offCommands[i] = new VoidCommand();//初始化为空命令。
        
        undoCommand = new VoidCommand();
    
    ~RemoteControl()
    
        for (int i = 0; i < 7; i++)
        
            delete onCommands[i];
            onCommands[i] = nullptr;
            delete offCommands[i];
            offCommands[i] = nullptr;
        
        delete undoCommand;
        undoCommand = nullptr;
    

    
    void setCommand(int slot, Command* onCommand, Command* offCommand)
    
        delete onCommands[slot];
        onCommands[slot] = onCommand;
        delete offCommands[slot];
        offCommands[slot] = offCommand;
    

    void onButtonWasPushed(int slot)
    
        onCommands[slot]->execute();
        undoCommand = onCommands[slot];
    


    void offButtonWasPushed(int slot)
    
        offCommands[slot]->execute();
        undoCommand = offCommands[slot];
    
    void undoButtonWasPushed()
    
        undoCommand->undo();
    

private:
    Command* onCommands[7];
    Command* offCommands[7];
    Command* undoCommand;
;

//遥控器使用者,相当于类图中的client
class RemoteControlTest
public:
    void test()
    
        RemoteControl remoteControl;
        //实例化接收者对象和命令对象
        Light light;
        LightOnCommand lightOnCommand(&light);
        LightOffCommand lightOffCommand(&light);
        TV tv;
        TVOnCommand tvOnCommand(&tv);
        TVOffCommand tvOffCommand(&tv);

        remoteControl.setCommand(0, &lightOnCommand, &lightOffCommand);
        remoteControl.setCommand(1, &tvOnCommand, &tvOffCommand);
        
        remoteControl.onButtonWasPushed(0);
        remoteControl.onButtonWasPushed(1);
        remoteControl.undoButtonWasPushed();
        remoteControl.offButtonWasPushed(0);
        remoteControl.offButtonWasPushed(1);
        remoteControl.undoButtonWasPushed();
    
;
int main()

    RemoteControlTest test;
    test.test();

执行结果如下

以上是关于命令模式C++实现的主要内容,如果未能解决你的问题,请参考以下文章

设计模式之命令模式C++实现

命令模式

JavaScript设计模式中的命令模式

JavaScript设计模式中的命令模式

两种语言实现设计模式(C++和Java)(十四:责任链模式)

1.12(设计模式)责任链模式