面向切面编程(AOP,Aspect Oriented Programming)是一种编程范式,允许开发者在不修改原有代码的情况下,为程序添加额外的功能。
AOP的核心概念是切面(Aspect),它表示在程序中跨越多个功能模块的关注点。例如,日志记录、事务管理和权限控制等功能都可以视为切面。通过将这些关注点从业务逻辑中分离出来,实现对程序行为的模块化,从而提高代码的可读性和可维护性。
关键词:关注点分离,核心逻辑和非核心逻辑分离,核心关注点和切面关注点
切面就是分布在各个业务模块里的非核心模块,大部分业务流程里都存在,因此aop就是为了把这些非核心逻辑关注点分离出来,比如日志模块。
在我们执行核心业务逻辑前后可以执行切面逻辑。
整个框架核心概念包括切面,切入点,通知,具体位置见下节。
参考《深入应用C++11代码优化与工程级别应用》
#include
#include
#define HAS_MEMBER(member)\
template \
struct has_member_##member\
{\
private:\
template \
static auto Check(int) -> decltype(std::declval().member(std::declval()...), std::true_type());\
template \
static std::false_type Check(...);\
public:\
enum {value = std::is_same(0)), std::true_type>::value};\
};\
HAS_MEMBER(Before)
HAS_MEMBER(After)
#if 1
template
struct Aspect
{
Aspect(Func&& f) : m_func(std::forward(f))
{
}
template
typename std::enable_if::value && has_member_After::value>::type
Invoke(Args&&... args, T&& aspect)
{
aspect.Before(std::forward(args)...);
m_func(std::forward(args)...);
aspect.After(std::forward(args)...);
}
template
typename std::enable_if::value && !has_member_After::value>::type
Invoke(Args&&... args, T&& aspect)
{
aspect.Before(std::forward(args)...);
m_func(std::forward(args)...);
}
template
typename std::enable_if::value && has_member_After::value>::type
Invoke(Args&&... args, T&& aspect)
{
m_func(std::forward(args)...);
aspect.After(std::forward(args)...);
}
#if 1 // 改进的,SFINAE语法
template
typename std::enable_if::value && has_member_After::value>::type
Invoke(Args&&... args, Head&& headAspect, Tail&&... tailAspect)
{
headAspect.Before(std::forward(args)...);
Invoke(std::forward(args)..., std::forward(tailAspect)...);
headAspect.After(std::forward(args)...);
}
template
typename std::enable_if::value && !has_member_After::value>::type
Invoke(Args&&... args, Head&& headAspect, Tail&&... tailAspect)
{
headAspect.Before(std::forward(args)...);
Invoke(std::forward(args)..., std::forward(tailAspect)...);
}
template
typename std::enable_if::value && has_member_After::value>::type
Invoke(Args&&... args, Head&& headAspect, Tail&&... tailAspect)
{
Invoke(std::forward(args)..., std::forward(tailAspect)...);
headAspect.After(std::forward(args)...);
}
#else // 书上的
template
void Invoke(Args&&... args, Head&& headAspect, Tail&&... tailAspect)
{
headAspect.Before(std::forward(args)...);
Invoke(std::forward(args)..., std::forward(tailAspect)...);
headAspect.After(std::forward(args)...);
}
#endif
private:
Func m_func;
};
// AOP 辅助函数
template
void Invoke(Func&& f, Args&&... args)
{
Aspect asp(std::forward(f));
asp.Invoke(std::forward(args)..., AP()...);
}
// test code
struct AA
{
void Before(int i)
{
std::cout << "Before from AA " << i << std::endl;
}
void After(int i)
{
std::cout << "After from AA " << i << std::endl;
}
};
struct BB
{
void Before(int i)
{
std::cout << "Before from BB " << i << std::endl;
}
void After(int i)
{
std::cout << "After from BB " << i << std::endl;
}
};
void Myfunc(int a)
{
std::cout << "real Myfunc function: " << a << std::endl;
}
#endif
int main(void)
{
Invoke(&Myfunc, 1);
return 0;
}
ps:书上针对多个切面的case时必须同时具备Before和After函数,见代码:
#else // 书上的
template
void Invoke(Args&&... args, Head&& headAspect, Tail&&... tailAspect)
{
headAspect.Before(std::forward(args)...);
Invoke(std::forward(args)..., std::forward(tailAspect)...);
headAspect.After(std::forward(args)...);
}
#endif
如何改进?
针对只包含Before或After和同时包含Before和After的场景编写函数模版,使用SFINAE技巧,核心就是利用std::enable_if类模版实现静多态(enable_if是基于C++中的SFINEA(Substitution failure is not anerror,中文直译即是“匹配失败不是错误”)实现的,SFINEA的意思是在实例化过程中,比如有三个模板,但凡能匹配到一个正确的,另外两个模板在实例化过程中即使报错,编译器也认为没问题),见代码:
#if 1 // 改进的,SFINAE语法
template
typename std::enable_if::value && has_member_After::value>::type
Invoke(Args&&... args, Head&& headAspect, Tail&&... tailAspect)
{
headAspect.Before(std::forward(args)...);
Invoke(std::forward(args)..., std::forward(tailAspect)...);
headAspect.After(std::forward(args)...);
}
template
typename std::enable_if::value && !has_member_After::value>::type
Invoke(Args&&... args, Head&& headAspect, Tail&&... tailAspect)
{
headAspect.Before(std::forward(args)...);
Invoke(std::forward(args)..., std::forward(tailAspect)...);
}
template
typename std::enable_if::value && has_member_After::value>::type
Invoke(Args&&... args, Head&& headAspect, Tail&&... tailAspect)
{
Invoke(std::forward(args)..., std::forward(tailAspect)...);
headAspect.After(std::forward(args)...);
}