IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 设计模式之命令模式C++实现 -> 正文阅读

[C++知识库]设计模式之命令模式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++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-05-21 18:44:48  更:2022-05-21 18:47:35 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/13 13:14:24-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码