C++之多层 if-else-if 结构优化(二)

发布时间:2023年12月23日

C++之多层 if-else-if 结构优化(一)-CSDN博客

接上面的内容继续讲解多层 if-else-if结构优化

6、使用责任链模式进行结构优化

????????责任链模式,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;
}

7、利用模板元编程的萃取原理来优化

????????萃取的实现方法:模板偏特化后使用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, 通过它可以提取到的类型有五种,如下:

  • input iterator:只读
  • output iterator:只写
  • forward iterator:允许写入,在此迭代器所形成的区间上进行读写操作
  • bidirectional iterator:可以双向移动
  • random access iterator:支持指针的所有算数操作

然后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的逻辑就比较清晰明了,通俗易懂。

C++之多层 if-else-if 结构优化(三)-CSDN博客

文章来源:https://blog.csdn.net/haokan123456789/article/details/135122930
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。