查看原文
其他

设计模式之代理模式

程序喵大人 程序喵大人 2022-08-22


【多数人都拥有自己不了解的能力和机会,都有可能做到未曾梦想的事情。——戴尔·卡耐基】


——卡耐基


前面的文章中程序喵分享过设计模式中所有的创建型模式,今天开始结构型模式的分享,结构型模式主要总结了一些类和对象组合的框架,这些框架通常用于解决某些特定场景的问题。 今天开始分享结构型模式的第一个模式:代理模式。

代理模式中通常有三个角色,一个是抽象产品角色,一个是具体产品角色,另一个是代理产品角色,这个代理产品角色的作用是什么呢?引入了代理产品角色是为了给原始的具体产品附加功能。注意这里代理模式附加的是跟原始类无关的功能,附加的如果是跟原始类有关的功能那是装饰器模式,后续程序喵会介绍。

代码实现如下:

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


往期推荐





您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存