文章目录
本文定义模式设计中行为型模式的解析,主要讲解模板方法模式、策略模式和命令模式。本文内容来至互联网内容的编辑修改,方便读者学习。如有侵权,第一时间联系作者删除。
1.模板方法模式
Template Method:定义一个操作中算法的骨架,而将一些步骤延迟到子类中。模板方法使子类可以重定义算法的某些特定步骤而不改变该算法的结构。
class AbstractClass
{
public:
virtual void PrimitiveOperation1()=0;
virtual void PrimitiveOperation2()=0;
void TemplateMethod();
virtual ~AbstractClass(){}
};
class ConcreteClass1 :public AbstractClass
{
public:
virtual void PrimitiveOperation1();
virtual void PrimitiveOperation2();
~ConcreteClass1(){}
};
class ConcreteClass2 :public AbstractClass
{
public:
virtual void PrimitiveOperation1();
virtual void PrimitiveOperation2();
~ConcreteClass2(){}
};
#include "Template.h"
#include <iostream>
void AbstractClass::TemplateMethod()
{
//模板方法定义算法的骨架
PrimitiveOperation1();
PrimitiveOperation2();
}
void ConcreteClass1::PrimitiveOperation1()
{
std::cout << "算法步骤1" << std::endl;
}
void ConcreteClass1::PrimitiveOperation2()
{
std::cout << "算法步骤2" << std::endl;
}
void ConcreteClass2::PrimitiveOperation1()
{
std::cout << "组成部分1" << std::endl;
}
void ConcreteClass2::PrimitiveOperation2()
{
std::cout << "组成部分2" << std::endl;
}
#include "Template.h"
int main()
{
AbstractClass *AC1 = new ConcreteClass1();
AC1->TemplateMethod();
AbstractClass *AC2 = new ConcreteClass2();
AC2->TemplateMethod();
delete AC1;
delete AC2;
}
模板方法模式,是最简单的面向对象行为模式,表示基类中存放不变的共有的接口函数和数据。而具体的实现放在子类中,同时尽量使用父类对象来进行统一的外部调用规划。
2.策略模式
Strategy:定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。该模式使得算法可独立于使用它的客户而变化。
#include <iostream>
using namespace std;
// Define the strategy type
typedef enum StrategyType
{
StrategyA,
StrategyB,
StrategyC
}STRATEGYTYPE;
// The abstract strategy
class Strategy
{
public:
virtual void AlgorithmInterface() = 0;
virtual ~Strategy() = 0; // 谢谢hellowei提出的bug,具体可以参见评论
};
Strategy::~Strategy()
{}
class ConcreteStrategyA : public Strategy
{
public:
void AlgorithmInterface()
{
cout << "I am from ConcreteStrategyA." << endl;
}
~ConcreteStrategyA(){}
};
class ConcreteStrategyB : public Strategy
{
public:
void AlgorithmInterface()
{
cout << "I am from ConcreteStrategyB." << endl;
}
~ConcreteStrategyB(){}
};
class ConcreteStrategyC : public Strategy
{
public:
void AlgorithmInterface()
{
cout << "I am from ConcreteStrategyC." << endl;
}
~ConcreteStrategyC(){}
};
class Context
{
public:
Context(STRATEGYTYPE strategyType)
{
switch (strategyType)
{
case StrategyA:
pStrategy = new ConcreteStrategyA;
break;
case StrategyB:
pStrategy = new ConcreteStrategyB;
break;
case StrategyC:
pStrategy = new ConcreteStrategyC;
break;
default:
break;
}
}
~Context()
{
if (pStrategy) delete pStrategy;
}
void ContextInterface()
{
if (pStrategy)
pStrategy->AlgorithmInterface();
}
private:
Strategy *pStrategy;
};
int main()
{
Context *pContext = new Context(StrategyA);
pContext->ContextInterface();
if (pContext) delete pContext;
}
3.命令模式
Command:将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。
我们去餐厅吃饭,我们是通过服务员来点菜,具体是谁来做这些菜和他们什么时候完成的这些菜,其实我们都不知道。抽象之,我们是“菜单请求者”,厨师是“菜单实现者”,两者之间是松耦合的,我们对这些菜的其他一些请求比如“撤销,重做”等,我们也不知道是谁在做。其实这就是本文要说的Command模式。将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤消的操作。下面实现一个简单撤销重做功能:
首先定义一个Command基类:
class Command
{
public:
Command(void);
virtual ~Command(void){};
public:
virtual void redo()=0;//重做
virtual void undo()=0;//撤销
};
有了基类,根据任务需要定义不同元操作的命令子类。ModifyCommand.h:
//修改命令类
class CModifyCommand :
public Command
{
public:
CModifyCommand(CBaseShape* shape,const QPointF &ptOffSet);
virtual ~CModifyCommand(void);
public:
virtual void redo();
virtual void undo();
private:
CBaseShape* m_shape;
QPointF m_ptOffSet;
};
ModifyCommand.cpp
#include "ModifyCommand.h"
CModifyCommand::CModifyCommand(CBaseShape* shape,const QPointF &ptOffSet )
{
m_shape = shape;
m_ptOffSet = ptOffSet;
}
CModifyCommand::~CModifyCommand(void)
{
}
void CModifyCommand::redo()
{
m_shape->Excute(m_ptOffSet);
}
void CModifyCommand::undo()
{
m_shape->Excute(-m_ptOffSet);
}
批处理命令类,BatchCommand.h:
#include "command.h"
#include <vector>
using namespace std;
//批处理命令类
class CBatchCommand :
public Command
{
public:
CBatchCommand(void);
virtual ~CBatchCommand(void);
public:
//添加子命令
void AddCommand(Command* cmd);
//执行子命令重做函数
virtual void redo();
//执行子命令撤销函数
virtual void undo();
private:
vector<Command*> m_vecCmds;//存储子命令
};
BatchCommand.cpp:
#include "BatchCommand.h"
CBatchCommand::CBatchCommand(void)
{
}
CBatchCommand::~CBatchCommand(void)
{
for (int i=0;i<m_vecCmds.size();++i)
{
if (NULL != m_vecCmds[i])
{
delete m_vecCmds[i];
m_vecCmds[i] = NULL;
}
}
m_vecCmds.clear();
}
void CBatchCommand::redo()
{
for (int i=0;i<m_vecCmds.size();++i)
{
m_vecCmds[i]->redo();
}
}
void CBatchCommand::undo()
{
for (int i=0;i<m_vecCmds.size();++i)
{
m_vecCmds[i]->undo();
}
}
void CBatchCommand::AddCommand( Command* cmd )
{
m_vecCmds.push_back(cmd);
}
定义了命令类,我们还要一个类来管理存储我们每次操作所产生的各种命令。CommandManager类,这里我用了两个容器来存储命令,一个存储撤销命令,一个存储重做命令。CommandManager.h:
#include "Command.h"
#include <vector>
using namespace std;
//命令管理类
class CommandManager
{
public:
CommandManager(void);
virtual ~CommandManager(void);
public:
//存储命令
virtual void StoreCommand(Command* cmd);
//清除所有命令
virtual void ClearAllCommand();
//清除重做命令
virtual void ClearRedoCommand();
//执行撤销命令
virtual void Undo() = 0;
//执行重做命令
virtual void Redo() = 0;
public:
vector<Command*> m_vecRedo;
vector<Command*> m_vecUndo;
};
CommandManager.cpp:
#include "CommandManager.h"
CommandManager::CommandManager(void)
{
}
CommandManager::~CommandManager(void)
{
}
void CommandManager::StoreCommand( Command* cmd )
{
m_vecUndo.push_back(cmd);
ClearRedoCommand();//添加新命令时,清除重做命令
}
void CommandManager::ClearAllCommand()
{
for (int i = 0;i<m_vecRedo.size();++i)
{
if (NULL != m_vecRedo[i])
{
delete m_vecRedo[i];
m_vecRedo[i] = NULL;
}
}
for (int i = 0;i<m_vecUndo.size();++i)
{
if (NULL != m_vecUndo[i])
{
delete m_vecUndo[i];
m_vecUndo[i] = NULL;
}
}
m_vecRedo.clear();
m_vecUndo.clear();
}
void CommandManager::ClearRedoCommand()
{
for (int i = 0;i<m_vecRedo.size();++i)
{
if (NULL != m_vecRedo[i])
{
delete m_vecRedo[i];
m_vecRedo[i] = NULL;
}
}
m_vecRedo.clear();
}
CommandHistoryManager 类,设计成了单例类,方便调用。
#include "commandmanager.h"
class CommandHistoryManager :
public CommandManager
{
public:
CommandHistoryManager(void);
virtual ~CommandHistoryManager(void);
public:
static CommandHistoryManager *GetInstance()
{
if (NULL == m_pCmdHistoryManager)
{
m_pCmdHistoryManager = new CommandHistoryManager();
}
return m_pCmdHistoryManager;
}
static void ReleaseInstance();
virtual void Undo();
virtual void Redo();
private:
static CommandHistoryManager* m_pCmdHistoryManager;
};
实现Undo(),Redo()函数:
#include "CommandHistoryManager.h"
CommandHistoryManager * CommandHistoryManager::m_pCmdHistoryManager = NULL;
CommandHistoryManager::CommandHistoryManager(void)
{
}
CommandHistoryManager::~CommandHistoryManager(void)
{
}
void CommandHistoryManager::Undo()
{
if ( m_vecUndo.size() <= 0 ) return;
Command* cmd = m_vecUndo.at(m_vecUndo.size()-1);
cmd->undo();
m_vecUndo.pop_back();
m_vecRedo.push_back(cmd);
}
void CommandHistoryManager::Redo()
{
if ( m_vecRedo.size() <= 0 ) return;
Command* cmd = m_vecRedo.at(m_vecRedo.size()-1);
cmd->redo();
m_vecRedo.pop_back();
m_vecUndo.push_back(cmd);
}
void CommandHistoryManager::ReleaseInstance()
{
if (NULL != m_pCmdHistoryManager)
{
delete m_pCmdHistoryManager;
m_pCmdHistoryManager = NULL;
}
}
命令使用方式:
//修改命令
CModifyCommand *mCmd = new CModifyCommand(this,ptOffset);
CommandHistoryManager::GetInstance()->StoreCommand(mCmd);
//批处理命令
CBatchCommand *bCmd = new CBatchCommand();
QList<CMyPointShape*>::iterator it;
for (it = m_myPointList.begin();it != m_myPointList.end();++it)
{
CModifyCommand *mCmd = new CModifyCommand(*it,ptOffset);
bCmd->AddCommand(mCmd);
}
CommandHistoryManager::GetInstance()->StoreCommand(bCmd);
4.作者答疑
如有疑问,请留言。