一、概述
模式名称:
CHAIN OF RESPONSIBILITY(职责链) (对象行为型模式)
意图:
使多个对象都有机会处理同一个请求,从而避免发送者和接受者之间的耦合关系。这些处理请求的对象组成一条链,
并沿着这条链传递该请求,直到有一个对象处理它,或者传递到最后一个节点,结束该链。
适用性:
1、有多个对象可以处理同一个请求,哪个对象处理该请求只有运行时才能确定。
2、想要在不明确指定接受者的情况下,向多个对象中的一个发送请求。
3、发送者只需要发送请求,而不用关注哪个对象会处理该次请求。
结构:
效果:
1、降低耦合度 该模式使一个对象无需知道是哪一个对象处理其请求。
2、增强了对象处理职责的灵活性,可以动态的添加或删除某些节点,来实现对象职责的动态变化。
3、不保证每次请求都会被处理
二、代码示例
这里举一个例子来深入了解职责链模式,我们假设有这么一个业务需求,根据输入的表达式,来进行加减乘除的处理。
输入的表达式为:a b,a-b,a*b,a/b
按照职责链的结构图,我们来设计一下这个业务的结构图:
根据类图生成代码:
接口类:
代码语言:javascript复制class ICalculate
{
public:
virtual int oCalc(const string& strRequest) = 0;
};
加法处理类:
代码语言:javascript复制//plus
class CPlusCalc : public ICalculate
{
public:
CPlusCalc(ICalculate* pCalc) : m_pCalc(pCalc) {};
~CPlusCalc() {if (nullptr != m_pCalc)
{
delete m_pCalc;
m_pCalc = nullptr;
}
};
virtual int oCalc(const string& strRequest) override
{
int nFind = strRequest.find(" ");
if (-1 != nFind)
{
cout << "加法处理" << endl;
string strLeft = strRequest.substr(0, nFind);
string strRight = strRequest.substr(nFind 1, strRequest.size() - nFind);
int nL = stoi(strLeft);
int nR = stoi(strRight);
int nResult = nL nR;
return nResult;
}
else
{
if (nullptr != m_pCalc)
{
return m_pCalc->oCalc(strRequest);
}
return -1;
}
};
private:
ICalculate* m_pCalc = nullptr;
};
减法处理类:
代码语言:javascript复制//minus
class CMinusCalc : public ICalculate
{
public:
CMinusCalc(ICalculate* pCalc) : m_pCalc(pCalc) {};
~CMinusCalc() {
if (nullptr != m_pCalc)
{
delete m_pCalc;
m_pCalc = nullptr;
}
};
virtual int oCalc(const string& strRequest) override
{
int nFind = strRequest.find("-");
if (-1 != nFind)
{
cout << "减法处理" << endl;
string strLeft = strRequest.substr(0, nFind);
string strRight = strRequest.substr(nFind 1, strRequest.size() - nFind);
int nL = stoi(strLeft);
int nR = stoi(strRight);
int nResult = nL - nR;
return nResult;
}
else
{
if (nullptr != m_pCalc)
{
return m_pCalc->oCalc(strRequest);
}
return -1;
}
};
private:
ICalculate* m_pCalc = nullptr;
};
乘法处理类:
代码语言:javascript复制//multiply
class CMultiplyCalc : public ICalculate
{
public:
CMultiplyCalc(ICalculate* pCalc) : m_pCalc(pCalc) {};
~CMultiplyCalc() {
if (nullptr != m_pCalc)
{
delete m_pCalc;
m_pCalc = nullptr;
}
};
virtual int oCalc(const string& strRequest) override
{
int nFind = strRequest.find("*");
if (-1 != nFind)
{
cout << "乘法处理" << endl;
string strLeft = strRequest.substr(0, nFind);
string strRight = strRequest.substr(nFind 1, strRequest.size() - nFind);
int nL = stoi(strLeft);
int nR = stoi(strRight);
int nResult = nL * nR;
return nResult;
}
else
{
if (nullptr != m_pCalc)
{
return m_pCalc->oCalc(strRequest);
}
return -1;
}
};
private:
ICalculate* m_pCalc = nullptr;
};
除法处理类:
代码语言:javascript复制//divide
class CDivideCalc : public ICalculate
{
public:
CDivideCalc(ICalculate* pCalc) : m_pCalc(pCalc) {};
~CDivideCalc() {
if (nullptr != m_pCalc)
{
delete m_pCalc;
m_pCalc = nullptr;
}
};
virtual int oCalc(const string& strRequest) override
{
int nFind = strRequest.find(R"(/)");
if (-1 != nFind)
{
cout << "除法处理" << endl;
string strLeft = strRequest.substr(0, nFind);
string strRight = strRequest.substr(nFind 1, strRequest.size() - nFind);
int nL = stoi(strLeft);
int nR = stoi(strRight);
if (0 == nR)
{
cout << "除数不可为0" << endl;
return -1;
}
int nResult = nL / nR;
return nResult;
}
else
{
if (nullptr != m_pCalc)
{
return m_pCalc->oCalc(strRequest);
}
return -1;
}
};
private:
ICalculate* m_pCalc = nullptr;
};
职责链的创建:
代码语言:javascript复制CDivideCalc* pDC = new CDivideCalc(nullptr);
CMultiplyCalc* pMUC = new CMultiplyCalc(pDC);
CMinusCalc* pMIC = new CMinusCalc(pMUC);
ICalculate* pCalc = new CPlusCalc(pMIC);
main函数:
代码语言:javascript复制int main()
{
//创建职责链
CDivideCalc* pDC = new CDivideCalc(nullptr);
CMultiplyCalc* pMUC = new CMultiplyCalc(pDC);
CMinusCalc* pMIC = new CMinusCalc(pMUC);
ICalculate* pCalc = new CPlusCalc(pMIC);
while (true)
{
string strRequest = "";
cin >> strRequest;
if (strRequest.empty())
{
break;
}
if (-1 != strRequest.find("exit"))
{
break;
}
int nCalcResult = pCalc->oCalc(strRequest);
cout << "结果:" << nCalcResult << endl;
}
delete pCalc;
}
运行结果:
计算公式不需要知道那个计算对象会处理我的请求,请求的发送者与受理者是松耦合的状态,职责链的对象可以调整顺序,添加和删除功能。不需要修改客户端的代码。
也不会影响到职责链中其他对象的实现。
此示例的对象结构如下:
对象交互时序图: