C++之多层 if-else-if 结构优化(一)-CSDN博客
接上面的内容继续讲解多层 if-else-if结构优化
????????责任链模式,Chain of responsibility,是GoF中的behavior pattern行为模式中的一种,在所有的行为模式中,设计的准则都为:使用对象的组合而不是对象的继承。责任链模式所描述的是:与其从已有的类中继承新的类,不如让你的类指向一个你要使用的已经存在的类。该模式用于解耦发送请求的客户与处理请求的对象,实现方式为持有一系列的handler对象,每个对象都能处理特定的请求,如果某个handler不能处理该请求,它将请求传递给链中的下一个对象。在链的末端,会有一个或多个通用的(generic)handler,用于对请求的默认处理。
该模式为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式。
????????责任链模式的重点是在“链”上,由一条链去处理相似的请求在链中决定谁来处理这个请
求,并返回相应的结果,其通用类图如下图所示。
根据责任链模式,设计类图如下:
代码如下:
#define MAX_PARAM 0x7FFFFFFF
class IMessageEntityBase
{
public:
virtual int func(int num) = 0;
};
class CMessageEntity1 : public IMessageEntityBase
{
public:
explicit CMessageEntity1(IMessageEntityBase* pNext) : m_pNext(pNext) {}
int func(int num) override {
if (num < 0) {
qDebug() << "类CMessageEntity1 调用函数 -- func() " << " 传递参数: num: " << num;
return num;
}
return m_pNext ? m_pNext->func(num) : MAX_PARAM;
}
private:
IMessageEntityBase* m_pNext;
};
class CMessageEntity2 : public IMessageEntityBase
{
public:
explicit CMessageEntity2(IMessageEntityBase* pNext) : m_pNext(pNext) {}
int func(int num) override {
if (num > 0 && num <= 10) {
qDebug() << "类CMessageEntity2 调用函数 -- func() " << " 传递参数: num: " << num;
return num;
}
return m_pNext ? m_pNext->func(num) : MAX_PARAM;
}
private:
IMessageEntityBase* m_pNext;
};
class CMessageEntity3 : public IMessageEntityBase
{
public:
explicit CMessageEntity3(IMessageEntityBase* pNext) : m_pNext(pNext) {}
int func(int num) override {
if (num > 10 && num <= 100) {
qDebug() << "类CMessageEntity3 调用函数 -- func() " << " 传递参数: num: " << num;
return num;
}
return m_pNext ? m_pNext->func(num) : MAX_PARAM;
}
private:
IMessageEntityBase* m_pNext;
};
class CMessageEntity4 : public IMessageEntityBase
{
public:
explicit CMessageEntity4(IMessageEntityBase* pNext) : m_pNext(pNext) {}
int func(int num) override {
if (num > 100 && num <= 1000) {
qDebug() << "类CMessageEntity4 调用函数 -- func() " << " 传递参数: num: " << num;
return num;
}
return m_pNext ? m_pNext->func(num) : MAX_PARAM;
}
private:
IMessageEntityBase* m_pNext;
};
class CMessageEntity5 : public IMessageEntityBase
{
public:
explicit CMessageEntity5(IMessageEntityBase* pNext) : m_pNext(pNext) {}
int func(int num) override {
if (num > 1000 && num <= 10000) {
qDebug() << "类CMessageEntity5 调用函数 -- func() " << " 传递参数: num: " << num;
return num;
}
return m_pNext ? m_pNext->func(num) : MAX_PARAM;
}
private:
IMessageEntityBase* m_pNext;
};
class CMessageEntityOverRange : public IMessageEntityBase
{
public:
explicit CMessageEntityOverRange(IMessageEntityBase* pNext) : m_pNext(pNext) {}
int func(int num) override {
if (num >= 10000) {
qDebug() << "类CMessageEntityOverRange 调用函数 -- func() " << " 传递参数: num: " << num;
return num;
}
return m_pNext ? m_pNext->func(num) : MAX_PARAM;
}
private:
IMessageEntityBase* m_pNext;
};
class CTestMessageEntity
{
public:
void setFunctor(IMessageEntityBase* pFunctor) {
m_functor = pFunctor;
}
int func(int num)
{
return m_functor->func(num);
}
private:
IMessageEntityBase* m_functor;
};
int main()
{
std::unique_ptr<IMessageEntityBase> pOverRanage(new CMessageEntityOverRange(nullptr));
std::unique_ptr<IMessageEntityBase> pFunctor5(new CMessageEntityOverRange(pOverRanage.get()));
std::unique_ptr<IMessageEntityBase> pFunctor4(new CMessageEntityOverRange(pFunctor5.get()));
std::unique_ptr<IMessageEntityBase> pFunctor3(new CMessageEntityOverRange(pFunctor4.get()));
std::unique_ptr<IMessageEntityBase> pFunctor2(new CMessageEntityOverRange(pFunctor3.get()));
std::unique_ptr<IMessageEntityBase> pFunctor1(new CMessageEntityOverRange(pFunctor2.get()));
CTestMessageEntity test;
test.setFunctor(pFunctor1.get());
int result = test.func(5);
result = test.func(80);
result = test.func(1500);
result = test.func(8000);
return 0;
}
????????萃取的实现方法:模板偏特化后使用using对偏特化的参数取别名;使用static成员;使用参数化萃取。
? ? ? ? 在我的博客?std::apply源码分析-CSDN博客?的 std::__invoke 实现部分也用到了类型萃取技术,可以去看看。
先看一下没有优化之前的代码:
MessageField.h
template <messageType TYPE, typename T, typename = std::enable_if_t<std::is_same<T,std::uint32_t>::value||
std::is_same<T,std::int32_t>::value ||
std::is_same<T,double>::value ||
std::is_same<T,std::uint64_t>::value ||
std::is_same<T,std::uint16_t>::value ||
std::is_same<T,float>::value>>
class CMessageStringTField : public CMessageStringField
{
using _base = CMessageStringField;
public:
explicit CMessageStringTField(){ }
CMessageStringTField(const CMessageStringTField& other)
: _base(other){
}
virtual ~CMessageStringTField(){}
public:
IMessageField* clone(const IMessageField* pSrc) const override{
return new CMessageStringTField(*dynamic_cast<const CMessageStringTField*>(pSrc));
}
messageType type() const override{
return TYPE;
}
bool isMultiValue() const override{
return true;
}
//和客户端交互的接口,kv一对一和一对多类型
bool getPacketValue(std::vector<std::uint64_t>& values) const override{
std::vector<T> data;
//[1] 将string转为T
if constexpr(std::is_same<T, std::uint64_t>::value){
gSplitString<T>(m_value, ::atoll, data);
}else if constexpr(std::is_same<T, std::uint32_t>::value){
gSplitString<T>(m_value, ::atol, data);
}else if constexpr(std::is_same<T, std::uint16_t>::value){
gSplitString<T>(m_value, ::atol, data);
}else if constexpr(std::is_same<T, std::int32_t>::value){
gSplitString<T>(m_value, ::atoi, data);
}else if constexpr(std::is_same<T, float>::value){
gSplitString<T>(m_value, ::atof, data);
}else if constexpr(std::is_same<T, double>::value){
gSplitString<T>(m_value, ::atof, data);
}else{
assert(0);
}
//[2] 将T转为std::uint64_t
for(auto& it : data){
values.push_back(transTToPUInt64(it));
}
return true;
}
//kv一对多类型
bool setPacketValue(const std::vector<std::uint64_t>& values) override{
m_value.clear();
for (int i = 0; i < values.size(); i++){
m_value += numConvertString(transPUInt64ToT<T>(values[i]));
if (i != values.size()-1){
m_value += ",";
}
}
return true;
}
...
};
gSplitString的实现如下:
template <typename T, typename FUNC = T(const char*),
typename = std::enable_if_t<std::is_arithmetic<T>::value>>
void gSplitString(const std::string& data, FUNC&& func, std::vector<T>& vecValue)
{
const char * split = ",";
std::unique_ptr<char[]> temp(new char[data.size()+1]);
memcpy(temp.get(), data.c_str(), data.size());
temp[data.size()] = '\0';
// 以逗号为分隔符拆分字符串
char *p = strtok(temp.get(), split);
while(p != NULL)
{
vecValue.push_back((T)func(p));
p = strtok(NULL, split);
}
}
在类成员函数getPacketValue中根据T的类型,调用不同的转换函数进行处理,基本都是字符串向数值类型转换,比较多的if constexpr 使得代码比较难看,扩展性也不好;那有没有什么办法根据T就是直接推导出使用那个转换函数呢,于是类型萃取技术就是粉墨登场了,其实类型萃取技术也不是什么高深的技术,在STL中很多地方都用到了类型萃取技术,如:迭代器iterator中iterator_category, 通过它可以提取到的类型有五种,如下:
然后STL的算法模块就根据?iterator_category 的不同调用不同的算法函数。
上面的代码我们也是根据这个原理来优化,优化后的代码如下:
MessageStringTFieldAssist.h
namespace xyLinkCorePrivate {
struct _tag_int64_value {};
struct _tag_uint32_value {};
struct _tag_int32_value {};
struct _tag_double_value {};
template <typename T>
void _splitString(_tag_int64_value, const std::string& value, std::vector<T>& data){
gSplitString<T>(value, ::atoll, data);
}
template <typename T>
void _splitString(_tag_uint32_value, const std::string& value, std::vector<T>& data){
gSplitString<T>(value, ::atol, data);
}
template <typename T>
void _splitString(_tag_int32_value, const std::string& value, std::vector<T>& data){
gSplitString<T>(value, ::atoi, data);
}
template <typename T>
void _splitString(_tag_double_value, const std::string& value, std::vector<T>& data){
gSplitString<T>(value, ::atof, data);
}
#define IS_INT64_VALUE(T) (std::is_same<T,std::uint64_t>::value||std::is_same<T,std::int64_t>::value)
#define IS_SIGNED_LESS32_VALUE(T) (std::is_same<T,std::uint32_t>::value||std::is_same<T,std::uint16_t>::value)
#define IS_UNSIGNED_LESS32_VALUE(T) (std::is_same<T,std::int32_t>::value||std::is_same<T,std::int16_t>::value)
template <typename T>
struct _value_type_category{
//typename千万不能省略,2023.12.14调试了大半天都没有搞明白是咋回事,一直编译报错
using type = typename std::conditional<IS_INT64_VALUE(T), _tag_int64_value,
typename std::conditional<IS_SIGNED_LESS32_VALUE(T), _tag_uint32_value,
typename std::conditional<IS_UNSIGNED_LESS32_VALUE(T), _tag_int32_value, _tag_double_value>::type>::type>::type;
};
#undef IS_INT64_VALUE
#undef IS_SIGNED_LESS32_VALUE
#undef IS_UNSIGNED_LESS32_VALUE
}
MessageField.h
#define IS_SUIT_TYPE(T) ( std::is_same<T,std::uint32_t>::value|| \
std::is_same<T,std::int32_t>::value || \
std::is_same<T,double>::value || \
std::is_same<T,std::uint64_t>::value || \
std::is_same<T,std::uint16_t>::value || \
std::is_same<T,float>::value )
template <messageType TYPE, typename T, typename = std::enable_if_t<IS_SUIT_TYPE(T)>>
//template <messageType TYPE, typename T, std::enable_if_t<IS_SUIT_TYPE(T),int> = 0>
class CMessageStringTField : public CMessageStringField
{
using _base = CMessageStringField;
public:
explicit CMessageStringTField(){ }
CMessageStringTField(const CMessageStringTField& other)
: _base(other){
}
virtual ~CMessageStringTField(){}
public:
IMessageField* clone(const IMessageField* pSrc) const override{
return new CMessageStringTField(*dynamic_cast<const CMessageStringTField*>(pSrc));
}
messageType type() const override{
return TYPE;
}
bool isMultiValue() const override{
return true;
}
public:
//和客户端交互的接口,kv一对一和一对多类型
bool getPacketValue(std::vector<std::uint64_t>& values) const override{
static_assert(IS_SUIT_TYPE(T),"T is not std::uint32_t or std::int32_t or float or double or std::uint16_t or std::uint64_t");
std::vector<T> data;
//[1] 将string转为T
using t = typename xyLinkCorePrivate::_value_type_category<T>::type;
xyLinkCorePrivate::_splitString(t{}, m_value, data);
//[2] 将T转为std::uint64_t
for(auto& it : data){
values.push_back(transTToPUInt64(it));
}
return true;
}
//kv一对多类型
bool setPacketValue(const std::vector<std::uint64_t>& values) override{
m_value.clear();
for (int i = 0; i < values.size(); i++){
m_value += numConvertString(transPUInt64ToT<T>(values[i]));
if (i != values.size()-1){
m_value += ",";
}
}
return true;
}
...
};
优化代码后,函数getPacketValue的逻辑就比较清晰明了,通俗易懂。