其他
设计模式之代理模式
【多数人都拥有自己不了解的能力和机会,都有可能做到未曾梦想的事情。——戴尔·卡耐基】 ——卡耐基 |
前面的文章中程序喵分享过设计模式中所有的创建型模式,今天开始结构型模式的分享,结构型模式主要总结了一些类和对象组合的框架,这些框架通常用于解决某些特定场景的问题。 今天开始分享结构型模式的第一个模式:代理模式。
代理模式中通常有三个角色,一个是抽象产品角色,一个是具体产品角色,另一个是代理产品角色,这个代理产品角色的作用是什么呢?引入了代理产品角色是为了给原始的具体产品附加功能。注意这里代理模式附加的是跟原始类无关的功能,附加的如果是跟原始类有关的功能那是装饰器模式,后续程序喵会介绍。
代码实现如下:
struct Product {
virtual ~Product() {}
virtual void Use() = 0;
};
struct ConcreteProduct : public Product {
void Use() override { std::cout << "use product\n"; }
};
struct ProductProxy : public Product {
private:
Product *product_;
public:
ProductProxy() { product_ = new ConcreteProduct(); }
~ProductProxy() { delete product_; }
void Use() override {
auto begin_use = [] { std::cout << "use product begin\n"; };
auto end_use = [] { std::cout << "use product end\n"; };
begin_use();
product_->Use();
end_use();
}
};
int main() {
ProductProxy proxy;
proxy.Use();
return 0;
}
上述代码即使用了代理模式为某个类附加了一些额外的功能,这里为具体产品类使用前后附加了一些log功能,平时开发过程中如果我们想要为某个类附加一些额外功能时,可以考虑使用代理模式。
C++中的切面编程(AOP)也可以理解为是一种代理模式:
#include <sys/time.h>
#include <ctime>
#include <iostream>
using namespace std;
#define HAS_MEMBER(member) \
template <typename T, typename... Args> \
struct has_member_##member { \
private: \
template <typename U> \
static auto Check(int) -> decltype(std::declval<U>().member(std::declval<Args>()...), std::true_type()); \
template <typename U> \
static std::false_type Check(...); \
\
public: \
enum { value = std::is_same<decltype(Check<T>(0)), std::true_type>::value }; \
};
HAS_MEMBER(Foo)
HAS_MEMBER(Before)
HAS_MEMBER(After)
template <typename Func, typename... Args>
struct Aspect {
Aspect(Func&& f) : m_func(std::forward<Func>(f)) {}
template <typename T>
typename std::enable_if<has_member_Before<T, Args...>::value && has_member_After<T, Args...>::value>::type Invoke(
Args&&... args, T&& aspect) {
aspect.Before(std::forward<Args>(args)...); //核心逻辑之前的切面逻辑
m_func(std::forward<Args>(args)...); //核心逻辑
aspect.After(std::forward<Args>(args)...); //核心逻辑之后的切面逻辑
}
template <typename T>
typename std::enable_if<has_member_Before<T, Args...>::value && !has_member_After<T, Args...>::value>::type Invoke(
Args&&... args, T&& aspect) {
aspect.Before(std::forward<Args>(args)...); //核心逻辑之前的切面逻辑
m_func(std::forward<Args>(args)...); //核心逻辑
}
template <typename T>
typename std::enable_if<!has_member_Before<T, Args...>::value && has_member_After<T, Args...>::value>::type Invoke(
Args&&... args, T&& aspect) {
m_func(std::forward<Args>(args)...); //核心逻辑
aspect.After(std::forward<Args>(args)...); //核心逻辑之后的切面逻辑
}
template <typename Head, typename... Tail>
void Invoke(Args&&... args, Head&& headAspect, Tail&&... tailAspect) {
headAspect.Before(std::forward<Args>(args)...);
Invoke(std::forward<Args>(args)..., std::forward<Tail>(tailAspect)...);
headAspect.After(std::forward<Args>(args)...);
}
private:
Func m_func; //被织入的函数
};
template <typename T>
using identity_t = T;
// AOP的辅助函数,简化调用
template <typename... AP, typename... Args, typename Func>
void Invoke(Func&& f, Args&&... args) {
Aspect<Func, Args...> asp(std::forward<Func>(f));
asp.Invoke(std::forward<Args>(args)..., identity_t<AP>()...);
}
struct TimeElapsedAspect {
void Before(int i) { m_lastTime = GetTime(); }
void After(int i) { cout << "time used: " << GetTime() - m_lastTime << endl; }
private:
long long m_lastTime;
long long GetTime() {
struct timeval time;
gettimeofday(&time, NULL);
return static_cast<long long>(time.tv_sec * 1000) + static_cast<long long>(time.tv_usec / 1000);
}
};
struct LoggingAspect {
void Before(int i) { std::cout << "begin" << std::endl; }
void After(int i) { std::cout << "end" << std::endl; }
};
void Func(int a) { cout << "Function: " << a << endl; }
int main() {
Invoke<LoggingAspect, TimeElapsedAspect>(&Func, 1); //织入方法
cout << "-----------------------" << endl;
Invoke<TimeElapsedAspect, LoggingAspect>(&Func, 1);
return 0;
}
通过AOP可以为某个函数前后编织切入一些方法,组成一个新的函数,这里也起到了代理作用,可以理解为一种静态代理。
参考资料
https://www.runoob.com/design-pattern/proxy-pattern.html
https://www.cnblogs.com/qicosmos/p/4772389.html
往期推荐