相关系列文章
目录
7.使用责任链模式进行结构优化
责任链模式,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;
}
8.利用模板元编程的萃取原理来优化
萃取的实现方法:模板偏特化后使用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;
}
...
};
里面的if constexpr(...) 表达式,编译器在编译时期使用编译时期表达式决定是否使用if语句或then部分或else部分(如果有的话)。如果其中一个分支条件成立,则另一部分(如果有的话)被丢弃,这样也就不会生成被丢弃部分的代码。但是,这并不意味着被丢弃的部分完全被忽略,它就像未使用模板的代码一样检查语法等。
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的逻辑就比较清晰明了,通俗易懂。
9.利用策略模式+工厂模式来优化
根据传入参数num的不同,调用不用的处理方法。那么就可以把这个处理流程分成两条线,一条线是处理方法,可以称之为处理策略,另外一条是根据num的不同,生成不同的处理策略,根据我们之前讲解的工厂模式,是不是有点像简单工厂的味道?实际上也是。
首先,我们把每个条件逻辑代码块,抽象成一个公共的接口,可以得出以下代码:
//抽象策略接口
class IMessageEntityBase
{
public:
virtual int func() = 0;
};
//具体策略1
class CMessageEntity1 : public IMessageEntityBase
{
public:
explicit CMessageEntity1(int num) : m_num(num) {}
int func() override {
qDebug() << "类CMessageEntity1 调用函数 -- func() " << " 传递参数: num: " << m_num;
return m_num;
}
private:
int m_num;
};
//具体策略2
class CMessageEntity2 : public IMessageEntityBase
{
public:
explicit CMessageEntity2(int num) : m_num(num) {}
int func() override {
qDebug() << "类CMessageEntity2 调用函数 -- func() " << " 传递参数: num: " << m_num;
return m_num;
}
private:
int m_num;
};
//具体策略3
class CMessageEntity3 : public IMessageEntityBase
{
public:
explicit CMessageEntity3(int num) : m_num(num) {}
int func() override {
qDebug() << "类CMessageEntity3 调用函数 -- func() " << " 传递参数: num: " << m_num;
return m_num;
}
private:
int m_num;
};
//具体策略4
class CMessageEntity4 : public IMessageEntityBase
{
public:
explicit CMessageEntity4(int num) : m_num(num) {}
int func() override {
qDebug() << "类CMessageEntity4 调用函数 -- func() " << " 传递参数: num: " << m_num;
return m_num;
}
private:
int m_num;
};
//具体策略5
class CMessageEntity5 : public IMessageEntityBase
{
public:
explicit CMessageEntity5(int num) : m_num(num) {}
int func() override {
qDebug() << "类CMessageEntity5 调用函数 -- func() " << " 传递参数: num: " << m_num;
return m_num;
}
private:
int m_num;
};
//具体策略6
class CMessageEntityOverRange : public IMessageEntityBase
{
public:
explicit CMessageEntityOverRange(int num) : m_num(num) {}
int func() override {
assert(0);
qDebug() << "类CMessageEntityOverRange 调用函数 -- func() " << " 传递参数: num: " << m_num;
return -1;
}
private:
int m_num;
};
接下来,我们再定义策略工厂类,用来管理具体策略类,如下:
//策略工厂
class CMessageEntityFactory
{
using R = std::shared_ptr<IMessageEntityBase>;
using FUNC = std::function<R(int)>;
public:
explicit CMessageEntityFactory() {
m_vecFactory.emplace_back([](int num)->R {
R pMessageEntiry;
if (num <= 0) {
pMessageEntiry.reset(new CMessageEntity1(num));
}
return pMessageEntiry;
});
m_vecFactory.emplace_back([](int num)->R {
R pMessageEntiry;
if (num > 0 && num <= 10) {
pMessageEntiry.reset(new CMessageEntity2(num));
}
return pMessageEntiry;
});
m_vecFactory.emplace_back([](int num)->R {
R pMessageEntiry;
if (num > 10 && num <= 100) {
pMessageEntiry.reset(new CMessageEntity3(num));
}
return pMessageEntiry;
});
m_vecFactory.emplace_back([](int num)->R {
R pMessageEntiry;
if (num > 100 && num <= 1000) {
pMessageEntiry.reset(new CMessageEntity4(num));
}
return pMessageEntiry;
});
m_vecFactory.emplace_back([](int num)->R {
R pMessageEntiry;
if (num > 1000 && num <= 10000) {
pMessageEntiry.reset(new CMessageEntity5(num));
}
return pMessageEntiry;
});
m_vecFactory.emplace_back([](int num)->R {
R pMessageEntiry;
if (num > 10000) {
pMessageEntiry.reset(new CMessageEntityOverRange(num));
}
return pMessageEntiry;
});
}
R create(int num) {
R temp;
for (int i = 0; i < m_vecFactory.size(); i++) {
if (temp = m_vecFactory[i](num)) {
break;
}
}
return temp;
}
private:
std::vector<FUNC> m_vecFactory;
};
使用了策略+工厂模式之后,代码变得简洁多了,如下:
int main()
{
CMessageEntityFactory factory;
auto pFunctor = factory.create(5);
auto result = pFunctor->func();
pFunctor = factory.create(80);
result = pFunctor->func();
pFunctor = factory.create(1500);
result = pFunctor->func();
pFunctor = factory.create(8000);
result = pFunctor->func();
return 0;
}