Skip to content

Instantly share code, notes, and snippets.

@grodtron
Created November 14, 2012 00:20
Show Gist options
  • Save grodtron/4069336 to your computer and use it in GitHub Desktop.
Save grodtron/4069336 to your computer and use it in GitHub Desktop.
Simple calculator program to demonstrate the command pattern in cpp
*.o
*.swp
*.swo
*.zip
test
#ifndef COMMAND_H_
#define COMMAND_H_
class Command {
public:
virtual void doit() = 0;
virtual void undo() = 0;
virtual ~Command(){}
};
#endif
#include "Commands.h"
AddCommand::AddCommand(int * target, int x)
: target(target), x(x)
{
}
void AddCommand::doit(){
*target += x;
}
void AddCommand::undo(){
*target -= x;
}
MultCommand::MultCommand(int * target, int x)
: target(target), x(x)
{
}
void MultCommand::doit(){
*target *= x;
}
void MultCommand::undo(){
*target /= x;
}
#ifndef COMMANDS_H_
#define COMMANDS_H_
#include "Command.h"
class AddCommand : public Command {
private:
int * target;
int x;
public:
AddCommand(int * target, int x);
void doit();
void undo();
};
class MultCommand : public Command {
private:
int * target;
int x;
public:
MultCommand(int * target, int x);
void doit();
void undo();
};
#endif
/*
* CommandStack.cpp
*
* Created on: 05.11.2012
* Author: dsinnig
*/
#include "CommandStack.h"
#include <iostream>
CommandStack::CommandStack (int size) : size(size), currentNumberOfCommands(0) {
commands = new Command*[size];
}
CommandStack::~CommandStack() {
clear(); // delete all of the commands
delete [] commands; // delete the array itself
}
Command* CommandStack::pop() {
return (currentNumberOfCommands > 0) ? commands[--currentNumberOfCommands] : NULL;
}
void CommandStack::push(Command* aCommand) {
if (currentNumberOfCommands < size)
commands[currentNumberOfCommands++] = aCommand;
}
bool CommandStack::empty() {
return currentNumberOfCommands == 0;
}
// Clear the entire stack, deleting all the commands that it held
void CommandStack::clear(){
// Loop over all of the commands in the stack
while(currentNumberOfCommands > 0){
--currentNumberOfCommands;
// delete the current command, and set the pointer
// to NULL (because it's a good habit to do so)
delete commands[currentNumberOfCommands];
commands[currentNumberOfCommands] = NULL;
}
}
/*
* CommandStack.h
*
* Created on: 05.11.2012
* Author: dsinnig
*/
#ifndef COMMANDSTACK_H_
#define COMMANDSTACK_H_
#include "Command.h"
class CommandStack {
public:
CommandStack (int size);
virtual ~CommandStack();
Command* pop();
void push(Command* aCommand);
bool empty();
void clear();
private:
int size;
int currentNumberOfCommands;
Command** commands;
};
#endif /* COMMANDSTACK_H_ */
#include "Invoker.h"
Invoker::Invoker()
: undoStack(16),
redoStack(16)
{
}
void Invoker::execute(Command * command){
command->doit();
undoStack.push(command);
redoStack.clear();
}
void Invoker::undo(){
if(!undoStack.empty()){
Command * command = undoStack.pop();
command->undo();
redoStack.push(command);
}
}
void Invoker::redo(){
if(!redoStack.empty()){
Command * command = redoStack.pop();
command->doit();
undoStack.push(command);
}
}
#ifndef INVOKER_H_
#define INVOKER_H_
#include "CommandStack.h"
#include "Command.h"
class Invoker {
private:
CommandStack undoStack;
CommandStack redoStack;
public:
Invoker();
void execute(Command *);
void undo();
void redo();
};
#endif
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
#include "Commands.h"
#include "Invoker.h"
// This function will ask the user for input in a loop
// and execute commands, or redo/undo them based on that
// input
void commandLoop(){
// The invoker of the commands
Invoker invoker;
// the receiver of the commands
int receiver;
// initialize the receiver
cout << "Set initial value to: ";
cin >> receiver;
while(1){
char in;
int val;
cout << "Enter command [ '+' (add) | '*' (multiply) | 'u' (undo) | 'r' (redo) ]: ";
cin >> in;
switch (in){
case '+':
cout << "Enter value: ";
cin >> val;
invoker.execute(new AddCommand(&receiver, val));
break;
case '*':
cout << "Enter value: ";
cin >> val;
invoker.execute(new MultCommand(&receiver, val));
break;
case 'u':
invoker.undo();
break;
case 'r':
invoker.redo();
break;
default:
// end the loop
return;
}
cout << "== Value is now: " << receiver << endl;
}
}
int main(){
commandLoop();
return 0;
}
.PHONY: clean all
all: test
%.o: %.cpp
g++ -ggdb -c $< -o $@
test: $(shell ls -1 *.cpp | sed 's/\.cpp/\.o/')
g++ -ggdb $^ -o $@
clean:
rm -f *.o
rm -f test
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment