design_pattern_command

This post implements the command pattern in the book <Head First Design Patterns>. TheCommand Pattern encapsulates a request as an object, thereby, letting you parametrize other objects with different requests, queue or log requests, and support undoable operations.

The command object encapsulates a request by binding together a set of actions on a specific receiver. To achieve this, it packages the actions and the receiver up into an object that exposes just one method,execute(). When called, execute() causes the actions to be invoked on the receiver. From the outside, no other objects really know what actions get performed on what receiver. They just know that if they call theexecute() method, their request will be served.

A command is a method call wrapped in an object. Commands are an object-oriented replacement for callbacks. The basic procedure for command pattern is

  1. Define a Command interface with a method signature like execute().
  2. Create one or more derived classes that encapsulate some subsetof the following: a "receiver" object, the method to invoke, the arguments to pass.
  3. Instantiate a Command object for each deferred execution request.
  4. Pass the Command object from the creator (aka sender) to the invoker (aka receiver).
  5. The invoker decides when to execute().

Let's implement the example in the book. First we define vendor's classes.

class Light{
private:
    std::string location;

public:
    Light(const std::string location_): location(location_){}

    void on() const{
		std::cout << location.c_str() << " light is on" << std::endl;
	}
	void off() const {
		std::cout << location.c_str() << " light is off" << std::endl;
	}
};

class TV{
private:
    mutable int channel;
	std::string location;

public:
    TV(const std::string location_):channel(0), location(location_){}

	void on() const{
		std::cout << location.c_str() << " TV is on" << std::endl;
	}
	void off() const{
		std::cout << location.c_str() << " TV is off" << std::endl;
	}
	void setInputChannel(){
		channel = 3;
		std::cout << location.c_str() << " Channel is set for VCR" << std::endl;
	}
};

class Stereo{
private:
    std::string location;

public:
    Stereo(std::string location):location(location_){}

	void on() const {
		std::cout << location.c_str() << " stereo is on" << std::endl;
	}

	void off() const {
		std::cout << location.c_str() << " stereo is off" << std::endl;
	}

	void setCD() const {
		std::cout << location.c_str() << " stereo is set for CD input" << std::endl;
	}

 	void setDVD() const {
		std::cout << location.c_str() << " stereo is set for DVD input" << std::endl;
	}

	void setRadio() const {
		std::cout << location.c_str() << " stereo is set for Radio" << std::endl;
	}

	void setVolume(int volume) const {
		// code to set the volume
		// valid range: 1-11 (after all 11 is better than 10, right?)
		std::cout << location.c_str() << " Stereo volume set to " << volume << std::endl;
	}
};

class Hottub{
private:
    mutable bool on;
	mutable int temperature;

public:
    Hottub():on(false), temperature(0){}

	void hottubon() const { on = true; }
	void hottuboff() const { on = false; }

	void bubblesOn() const {
		if(on){
			std::cout << "Hottub is bubbling!" << std::endl;
		}
	}

	void bubblesOff() const {
		if(on){
			std::cout << "Hottub is not bubbling" << std::endl;
		}
	}

	void jetsOn() const {
		if(on){
			std::cout << "Hottub jets are on" << std::endl;
		}
	}

	void jetsOff() const {
		if(on) {
			std::cout << "Hottub jets are off" << std::endl;
		}
	}

	void setTemperature(int temperature_) {
		temperature = temperature_;
	}

	void heat() const {
        temperature = 105;
		std::cout << "Hottub is heating to a steaming 105 degrees" << std::endl;
	}

	void cool() const {
		temperature = 98;
		std::cout << "Hottub is cooling to 98 degrees" << std::endl;
	}
};

class GarageDoor {
private:
    std::string location;

public:
    GarageDoor(const std::string location_):location(location_) {}

 	void up() const {
		std::cout << location.c_str() << " Door is Up" << std::endl;
	}

	void down() const {
		std::cout << location.c_str() << " Door is Down" << std::endl;
	}

	void stop() const {
		std::cout << location.c_str() << " Door is Stopped" << std::endl;
	}

	void lightOn() const {
		std::cout << location.c_str() << " light is on" << std::endl;
	}

	void lightOff() const {
		std::cout << location.c_str() << " light is off" << std::endl;
	}
};

class CeilingFan {
private:
    mutable int level;
	std::string location;

public:
    static const int HIGH = 2;
	static const int MEDIUM = 1;
	static const int LOW = 0;

    CeilingFan(const std::string location_):level(LOW), location(location_) {}

	void high() const {
		level = HIGH;
		std::cout << location.c_str() << " ceiling fan is on high" << std::endl;
	}

	void medium() const {
		level = MEDIUM;
		std::cout << location.c_str() << " ceiling fan is on medium" << std::endl;
	}
	public: void low() const {
		level = LOW;
		std::cout << location.c_str() << " ceiling fan is on low" << std::endl;
	}
	public: void off() const {
		level = 0;
		std::cout << location.c_str() << " ceiling fan is off" << std::endl;
	}
	public: int getSpeed() const {
		return level;
	}
};
Then we define command process

class Command {
public:
    virtual void execute() const = 0;
};

class LightOnCommand : public Command {
private:
    const Light* light;

public:
    LightOnCommand(const Light* light_) : light(light_){}

	void execute() const {
		light->on();
	}

	~LightOnCommand(){
        delete light;
        light = NULL;
	}
};

class LightOffCommand : public Command {
private:
    const Light* light;

public:
    LightOffCommand(const Light* light_) : light(light_){}

	void execute() const {
		light->off();
	}

	~LightOffCommand(){
        delete light;
        light = NULL;
	}
};

class LivingroomLightOnCommand : public Command {
private:
    const Light* light;

public:
    LivingroomLightOnCommand(const Light* light_):light(light_){}

	void execute() const {
		light->on();
	}

	~LivingroomLightOnCommand(){
        delete light;
        light = NULL;
	}
};

class LivingroomLightOffCommand : public Command {
private:
    const Light* light;

public:
    LivingroomLightOffCommand(const Light* light_):light(light_){}

	void execute() const {
		light->off();
	}

	~LivingroomLightOffCommand(){
        delete light;
        light = NULL;
	}
};

class NoCommand : public Command{
public:
    void execute() const {};
};

The remote control class is given by

class RemoteControl {
private:
    static const int SLOTS = 7;
    Command* onCommands[SLOTS];
	Command* offCommands[SLOTS];
	Command* noCommand;

	RemoteControl(const RemoteControl& );  // Disable copy constructor
	void operator=(const RemoteControl& ); // Disable assignment operator

public:
    RemoteControl() {
		noCommand = new NoCommand();
		for(int i = 0; i < SLOTS; i++) {
			onCommands[i]  = noCommand;
			offCommands[i] = noCommand;
		}
	}

	~RemoteControl() {
	    for(int i = 0; i < SLOTS; i++) {
			delete onCommands[i];
			delete offCommands[i];
			onCommands[i] = NULL;
			offCommands[i] = NULL;
		}
		delete noCommand;
		noCommand = NULL;
	}

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

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

	void offButtonWasPushed(int slot) const {
		offCommands[slot]->execute();
	}

	void toString() const {
		std::cout << "\n------ Remote Control -------\n" << std::endl;
		for( int i = 0; i < SLOTS; i++ ) {
			std::cout << "[slot " << i << "] ";
			std::cout << typeid( *onCommands[i] ).name();
			std::cout << "    ";
			std::cout << typeid( *offCommands[i] ).name();
			std::cout << std::endl;
		}
	}
};

The main function is

#include <iostream>
#include <typeinfo>
#include <./vendor.hpp>
#include <./command.hpp>
#include <./remotecontrol.hpp>
using namespace std;

int main()
{
    RemoteControl* rc = new RemoteControl();

    Light* livingRoomLight = new Light("Living Room");
	Light* kitchenLight = new Light("Kitchen");

	LightOnCommand* livingRoomLightOn = new LightOnCommand(livingRoomLight);
    LightOffCommand* livingRoomLightOff = new LightOffCommand(livingRoomLight);
	LightOnCommand* kitchenLightOn = new LightOnCommand(kitchenLight);
	LightOffCommand* kitchenLightOff = new LightOffCommand(kitchenLight);

	rc->setCommand( 0, livingRoomLightOn, livingRoomLightOff);
	rc->setCommand( 1, kitchenLightOn, kitchenLightOff);

	rc->onButtonWasPushed(0);
	rc->offButtonWasPushed(0);
	rc->onButtonWasPushed(1);
	rc->offButtonWasPushed(1);

	delete rc;

    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值