C++设计模式七--CommandPattern(命令模式)

本文介绍命令模式的基本概念,通过一个遥控器控制电灯和音响的示例详细解释了命令模式的应用方式,展示了如何通过命令对象解耦调用者与接收者。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

定义

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

要点

  1)命令模式将调用者接受者对象解耦。
  2)被解耦的两者之间是通过命令对象进行沟通的。命令对象封装了接受者和一个或者一组动作
  3)调用者通过调用命令对象的execute()发出请求,这会使得接收者的动作被调用。
  4)调用者可以接受命令对象当做参数,甚至在运行时动态地进行。
  5)命令可以支持撤销,做法是实现一个undo()方法来回到execute()倍执行前的状态。
  6)命令可以用来实现日志事务系统

类图

这里写图片描述
Invoker:调用者持有一个命令对象,并在某个时间点调用命令对象的execute()方法,将请求付诸行动。
Command:为所有命令声明一个接口。调用命令对象的execute()方法,就可以就可以让接收者进行相关的动作。这个接口也具备一个undo()方法。
Receiver:接收者知道如何进行必要的工作,实现这个请求。任何类都可以做接收者。

示例

  下面模拟一个遥控器程序,来控制电灯和音响的开关。
Light.h

#ifndef LIGHT_H
#define LIGHT_H

#include <string>
#include <iostream>


using std::string;
using std::cout;
using std::endl;

// 灯(Receiver)
class Light
{
public:
    Light(string n): name(n)
    {}
    ~Light(){}
    void on()
    {
        cout << name << " is on" << endl;
    }
    void off()
    {
        cout << name << " is off" << endl;
    }
private:
    string name;
};

#endif

Stereo.h

#ifndef STEREO_H
#define STEREO_H

#include <string>
#include <iostream>

using std::string;
using std::cout;
using std::endl;

// 音响(Receiver)
class Stereo
{
public:
    Stereo(string n): name(n)
    {}
    ~Stereo(){}
    void on()
    {
        cout << name << " is on" << endl;
    }
    void off()
    {
        cout << name << " is off" << endl;
    }
private:
    string name;
};
#endif

Command.h

#ifndef COMMAND_H
#define COMMAND_H

#include "Light.h"
#include "Stereo.h"

// 命令接口
class Command
{
public:
    Command(){}
    virtual~Command(){}
    virtual void execute() = 0;
    virtual void undo() = 0;
};

// 空命令
class NoCommand : public Command 
{
public:
    NoCommand(){}
    ~NoCommand(){}
    void execute(){}
    void undo(){}
};

// 开灯命令
class LightOnCommand: public Command
{
public:
    LightOnCommand(Light *l): light(l)
    {
    }
    ~LightOnCommand(){}

    void execute()
    {
        light->on();
    }
    void undo()
    {
        light->off();
    }
private:
    Light *light;
};

// 关灯命令
class LightOffCommand: public Command
{
public:
    LightOffCommand(Light *l): light(l)
    {
    }
    ~LightOffCommand(){}

    void execute()
    {
        light->off();
    }
    void undo()
    {
        light->on();
    }
private:
    Light *light;
};

// 开音响命令
class StereoOnCommand: public Command
{
public:
    StereoOnCommand(Stereo *s): stereo(s)
    {
    }
    ~StereoOnCommand(){}

    void execute()
    {
        stereo->on();
    }
    void undo()
    {
        stereo->off();
    }
private:
    Stereo *stereo;
};

// 关音响命令
class StereoOffCommand: public Command
{
public:
    StereoOffCommand(Stereo *s): stereo(s)
    {
    }
    ~StereoOffCommand(){}

    void execute()
    {
        stereo->off();
    }
    void undo()
    {
        stereo->on();
    }
private:
    Stereo *stereo;
};


// 遥控器(Invoker)
class RemoteControl 
{
private:
    Command* onCommands[7];    // 最多控制7个设备
    Command* offCommands[7];
    Command* undoCommand;
    Command* noCommand;
public:
    RemoteControl()
    {
        noCommand = new NoCommand();
        for (int i=0; i<7; i++) {
            onCommands[i] = noCommand;
            offCommands[i] = noCommand;
        }
        undoCommand = noCommand;
    }
    ~RemoteControl()
        {
            delete noCommand;
        }
    void setCommand(int slot, Command* onCommand, Command* offCommand)
    {
        onCommands[slot] = onCommand;
        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();
    }
};

// 批量命令(Invoker)
class MacroCommand: public Command
{
private:
    Command** command;
    int cnt;
public:
    MacroCommand(Command** cmd, int c): command(cmd), cnt(c)
    {
    }
    ~MacroCommand(){}

    void execute()
    {
        for (int i=0; i<cnt; i++) {
            command[i]->execute();
        }
    }
    void undo()
    {
       for (int i=0; i<cnt; i++) {
            command[i]->undo();
        }
    }
};
#endif

main.cpp

#include "Command.h"

int main()
{
    Light *light = new Light("Simple light");
    Stereo *stereo = new Stereo("Cool stereo");

    LightOnCommand *loc = new LightOnCommand(light);
    LightOffCommand *lofc = new LightOffCommand(light);
    StereoOnCommand *soc = new StereoOnCommand(stereo);
    StereoOffCommand *sofc = new StereoOffCommand(stereo);

    RemoteControl* remoteControl = new RemoteControl();

    remoteControl->setCommand(0, loc, lofc);
    remoteControl->setCommand(1, soc, sofc);

    remoteControl->onButtonWasPushed(0);
    remoteControl->offButtonWasPushed(0);

    remoteControl->onButtonWasPushed(1);
    remoteControl->offButtonWasPushed(1);
    remoteControl->undoButtonWasPushed();

    cout << "==============================" << endl;

    Command* cmd[2] = {loc, soc};
    MacroCommand* macroCommand = new MacroCommand(cmd, 2);
    macroCommand->execute();
    macroCommand->undo();

    delete macroCommand;
    delete remoteControl;
    delete sofc;
    delete soc;
    delete lofc;
    delete loc;
    delete stereo;
    delete light;

    return 0;
}

Makefile

CXX = g++
CFLAGS = -Wall
LDFLAGS = 

target = res
srcs = main.cpp
objs = $(srcs:.cpp=.o)
headers = $(wildcard *.h)


.PHONY: all
all: $(target)

$(target): $(objs) $(headers)
    $(CXX) $(LDFLAGS) -o $(target) $(objs)

$(objs):%.o:%.cpp
    $(CXX) $(CFLAGS) -c -o $@ $<

clean:
    rm -f $(target) *.o
测试

测试结果如下图所示:
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值