代理模式

代理模式

简单回顾下创建型模式

  1. 单例模式用来创建全局唯一的对象
  2. 工厂模式用来创建不同但是相关类型的对象(继承同一父类或者接口的一组子类), 由给定的参数来决定创建哪种类型的对象
  3. 建造者模式是用来创建复杂对象, 可以通过设置不同的可选参数, “定制化”地创建不同的对象
  4. 原型模式针对创建成本比较大的对象, 利用对已有对象进行复制的方式进行创建, 以达到节省创建时间的目的

接下来就是结构型模型

结构型模式包括:代理模式、桥接模式、装饰器模式、适配器模式、门面模式、组合模式、享元模式

原理

在不改变原始类(或叫被代理类)代码的情况下, 通过引入代理类来给原始类附加功能.

下述有个业务接口.

// 接口虚类
class Subject {
 public:
  virtual void method() = 0;
  virtual void print() = 0;
};
//业务实现类
class RealSubject : public Subject {
 public:
  void method() { print(); }
  void print() { std::cout << "real method" << std::endl; }
};

若我想在这个业务上加个功能, 访问时间, 执行时长 或者其他的扩展业务

  1. 扩展代码侵入业务代码, 跟业务代码高度耦合, 而且以后需要替换成其他扩展成本比较大
  2. 扩展代码跟业务代码无关, 不应该放一起. 一个类最好职责单一, 只需要关心业务的处理

假设我这边需要简单加个日期打印

// Log类
class Log {
 public:
  Log() {}
  std::string getTime() {
    time_t t = time(NULL);
    char ch[64] = {0};
    // 年-月-日 时:分:秒
    strftime(ch, sizeof(ch) - 1, "%Y-%m-%d %H:%M:%S", localtime(&t));
    return ch;
  }
};

下面通过代理模式添加时间日志输出

//代理类
class StaticProxy : public Subject {
 public:
  StaticProxy() {
    subject = new RealSubject();
    log = new Log();
  }
  ~StaticProxy() {
    delete subject;
    delete log;
  }
  void method() {
    std::cout << log->getTime() << ": "
              << "static proxy start" << std::endl;
    subject->method();
    std::cout << log->getTime() << ": "
              << "static proxy end" << std::endl;
  }
  void print() {}

 private:
  RealSubject* subject;
  Log* log;
};

调用方式

std::shared_ptr<Subject> sub = nullptr;
std::cout << "-----Orgin print-----" << std::endl;
sub = std::make_shared<RealSubject>();
sub->method();
std::cout << "-----Proxy Pattern-----" << std::endl;
sub = std::make_shared<StaticProxy>();
sub->method();

效果

./bin/design/Proxy
-----Orgin print-----
real method
-----Proxy Pattern-----
2023-10-13 10:08:37: static proxy start
real method
2023-10-13 10:08:37: static proxy end

这样就可以在不入侵原有业务代码的基础上扩展功能

但是 代码实现还是有点问题

  1. 我们需要在代理类中,将原始类中的所有的接口,都重新实现一遍,并且为每个方法都附加相似的代码逻辑.
  2. 如果要添加的附加功能的类有不止一个,我们需要针对每个类都创建一个代理类。

我们可以使用动态代理来解决这个问题

就是我们不事先为每个原始类编写代理类,而是在运行的时候,动态地创建原始类对应的代理类,然后在系统中用代理类替换掉原始类。

业务2接口

// 接口虚类2
class Subject2 {
 public:
  virtual void method2() = 0;
  virtual void print2() = 0;
};
// 业务实现类2
class RealSubject2 : public Subject2 {
 public:
  void method2() { print2(); }
  void print2() { std::cout << "real2 method" << std::endl; } 
};

代理类

template <class T>
class DynamicProxy : public T {
 public:
  DynamicProxy(std::function<void()> func) : func(func), log(new Log) {}
  ~DynamicProxy() { delete log; }
  void extend() {
    std::cout << log->getTime() << ": "
              << "dynamic proxy start" << std::endl;
    func();
    std::cout << log->getTime() << ": "
              << "dynamic proxy end" << std::endl;
  }
  void method() { extend(); }
  void method2() { extend(); }

 private:
  std::function<void()> func;
  Log* log;
};

调用方式

  std::cout << "-----Dynamic Proxy Pattern-----" << std::endl;
  std::shared_ptr<Subject> sub1 = std::make_shared<DynamicProxy<RealSubject>>(
      std::bind(&RealSubject::method, RealSubject()));
  sub1->method();
  std::shared_ptr<Subject2> sub2 = std::make_shared<DynamicProxy<RealSubject2>>(
      std::bind(&RealSubject2::method2, RealSubject2()));
  sub2->method2();

效果

./bin/design/Proxy
-----Dynamic Proxy Pattern-----
2023-10-13 10:34:48: dynamic proxy start
real method
2023-10-13 10:34:48: dynamic proxy end
2023-10-13 10:34:48: dynamic proxy start
real2 method
2023-10-13 10:34:48: dynamic proxy end

通过动态代理方式(模版增加通用性)

  1. 可以通过绑定函数的方式动态添加需要增加扩展的业务函数接口
  2. 只需要实现增加扩展的接口, 不需要全部实现基类所以接口

适用

代理模式常用在业务系统中开发一些非功能性需求,比如:监控、统计、鉴权、限流、事务、幂等、日志。

我们将这些附加功能与业务功能解耦,放到代理类统一处理,让程序员只需要关注业务方面的开发。
代码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值