代理模式及优化 - 实践

代理模式(Proxy Pattern)是一种结构型设计模式,它允许通过创建一个代理对象来控制对另一个对象(称为真实对象或被代理对象)的访问。代理对象充当客户端和真实对象之间的中介,客户端通过代理对象间接访问真实对象,从而可以在不改变真实对象的前提下添加额外的功能或控制逻辑。

一、介绍

核心概念
  1. 主题接口(Subject Interface)
    • 定义真实对象和代理对象的共同接口,确保客户端可以统一地使用它们。
    • 客户端通过此接口与代理和真实对象交互。
  2. 真实主题(Real Subject)
    • 实现主题接口的具体对象,提供实际的业务功能。
    • 通常是开销较大或需要特殊处理的对象。
  3. 代理(Proxy)
    • 实现与真实主题相同的接口,持有对真实主题的引用。
    • 控制对真实主题的访问,并可以在调用前后添加额外逻辑。
优点
  1. 解耦客户端与真实对象
    • 客户端无需知道真实对象的具体实现,降低耦合度
  2. 增强安全性
    • 通过代理控制访问权限,保护敏感资源
  3. 提高性能
    • 延迟加载和缓存机制优化资源利用
  4. 简化复杂系统
    • 隐藏网络通信、资源管理等复杂细节
  5. 符合开闭原则
    • 可以在不修改真实对象的情况下添加新的代理功能
缺点
  1. 增加系统复杂度
    • 多层代理或复杂代理逻辑可能导致代码难以理解
  2. 性能开销
    • 代理调用会引入额外的处理步骤,可能影响性能
  3. 可能导致设计过度
    • 如果不需要额外控制或功能,使用代理会显得冗余
代理模式的使用时机
  1. 延迟初始化(虚拟代理)
    • 当创建开销大的对象时,通过代理延迟到真正需要时再创建
    • 如示例中的图片加载,首次访问时才加载资源
  2. 访问控制(保护代理)
    • 限制对真实对象的访问权限
    • 例如:验证用户权限后才允许访问敏感资源
  3. 远程对象代理(远程代理)
    • 为位于不同地址空间的对象提供本地接口
    • 如分布式系统中,代理负责网络通信细节
  4. 操作监控(智能引用代理)
    • 在访问对象时附加额外操作
    • 例如:引用计数、缓存、日志记录等
  5. 资源优化(缓存代理)
    • 缓存频繁访问的对象结果
    • 如数据库查询结果的临时缓存

二、实现

#include <iostream>
  #include <string>
    // 主题接口
    class Image
    {
    public:
    virtual void display() const = 0;
    virtual ~Image() = default;
    };
    // 真实主题
    class RealImage
    : public Image {
    private:
    std::string filename;
    public:
    explicit RealImage(const std::string& filename) : filename(filename) {
    loadFromDisk();
    }
    void display() const override {
    std::cout <<
    "Displaying image: " << filename << std::endl;
    }
    private:
    void loadFromDisk() const {
    std::cout <<
    "Loading image: " << filename << std::endl;
    }
    };
    // 代理
    class ProxyImage
    : public Image {
    private:
    std::string filename;
    mutable RealImage* realImage = nullptr;
    public:
    explicit ProxyImage(const std::string& filename) : filename(filename) {
    }
    ~ProxyImage() override {
    delete realImage;
    }
    void display() const override {
    if (!realImage) {
    realImage = new RealImage(filename);
    }
    realImage->
    display();
    }
    };
    // 客户端代码
    int main() {
    Image* image = new ProxyImage("test.jpg");
    // 第一次调用,会加载并显示
    image->
    display();
    std::cout << std::endl;
    // 第二次调用,直接显示(已加载)
    image->
    display();
    delete image;
    return 0;
    }
实现注意事项
  1. 接口一致性
    • 代理必须实现与真实对象相同的接口,确保透明替换
  2. 生命周期管理
    • 代理需要正确管理真实对象的生命周期,避免内存泄漏
  3. 线程安全
    • 在多线程环境中,代理需要处理好并发访问问题
  4. 避免过度使用
    • 仅在确实需要控制访问或增强功能时使用代理模式
常见应用场景
  1. 远程代理(Remote Proxy)

    • 为位于不同地址空间的对象提供本地接口
    • 例如:分布式系统中的远程方法调用(RMI)、Web服务客户端代理
  2. 虚拟代理(Virtual Proxy)

    • 延迟创建开销大的对象,直到真正需要时才实例化
    • 例如:图片懒加载、大型文档的部分内容加载
  3. 保护代理(Protection Proxy)

    • 控制对敏感对象的访问权限
    • 例如:基于角色的访问控制、操作系统文件权限管理
  4. 智能引用代理(Smart Reference Proxy)

    • 在访问对象时附加额外操作,如引用计数、缓存、资源释放等
    • 例如:智能指针、COM组件的生命周期管理
  5. 缓存代理(Caching Proxy)

    • 缓存频繁访问的对象结果,提高性能
    • 例如:数据库查询结果缓存、CDN缓存静态资源

三、优化

  1. 内存管理:使用智能指针避免内存泄漏
  2. 线程安全:通过双重检查锁定支持多线程
  3. 功能扩展
    • 缓存机制减少重复加载
    • 日志记录增强可观测性
    • 访问控制提升安全性
  4. 灵活性
    • 工厂模式解耦对象创建
    • 代理可组合使用
  5. 性能优化
    • 延迟加载减少初始开销
    • 缓存复用已有资源

用户会话管理系统

#include <iostream>
  #include <string>
    #include <memory>
      #include <unordered_map>
        #include <mutex>
          #include <chrono>
            #include <vector>
              // 会话管理系统
              class Session
              {
              public:
              virtual std::string getRole() const = 0;
              virtual ~Session() = default;
              };
              class GuestSession
              : public Session {
              public:
              std::string getRole() const override {
              return "guest";
              }
              };
              class AdminSession
              : public Session {
              public:
              std::string getRole() const override {
              return "admin";
              }
              };
              class SessionManager
              {
              private:
              static SessionManager* instance;
              std::unique_ptr<Session> currentSession;
                SessionManager() : currentSession(std::make_unique<GuestSession>
                  ()) {
                  }
                  SessionManager(const SessionManager&
                  ) = delete;
                  SessionManager&
                  operator=(const SessionManager&
                  ) = delete;
                  public:
                  static SessionManager* getInstance() {
                  if (!instance) {
                  instance = new SessionManager();
                  }
                  return instance;
                  }
                  void loginAsAdmin() {
                  std::cout <<
                  "Logging in as admin..." << std::endl;
                  currentSession = std::make_unique<AdminSession>
                    ();
                    }
                    void logout() {
                    std::cout <<
                    "Logging out..." << std::endl;
                    currentSession = std::make_unique<GuestSession>
                      ();
                      }
                      const Session&
                      getSession() const {
                      return *currentSession;
                      }
                      };
                      SessionManager* SessionManager::instance = nullptr;

代理模式优化

// 主题接口
class Image
{
public:
virtual void display() const = 0;
virtual ~Image() = default;
};
// 真实主题
class RealImage
: public Image {
private:
std::string filename;
public:
explicit RealImage(const std::string& filename) : filename(filename) {
loadFromDisk();
}
void display() const override {
std::cout <<
"Displaying image: " << filename << std::endl;
}
const std::string&
getFilename() const {
return filename;
}
private:
void loadFromDisk() const {
std::cout <<
"Loading image: " << filename << std::endl;
}
};
// 代理实现
// 延迟加载代理
class ProxyImage
: public Image {
private:
std::string filename;
mutable std::unique_ptr<RealImage> realImage;
  public:
  explicit ProxyImage(const std::string& filename) : filename(filename) {
  }
  void display() const override {
  if (!realImage) {
  std::cout <<
  "Creating real image for " << filename << std::endl;
  realImage = std::make_unique<RealImage>
    (filename);
    }
    realImage->
    display();
    }
    };
    // 缓存代理
    class CachedProxyImage
    : public Image {
    private:
    std::string filename;
    mutable std::shared_ptr<RealImage> realImage;
      static std::unordered_map<std::string, std::weak_ptr<RealImage>> cache;
        static std::mutex cacheMutex;
        public:
        explicit CachedProxyImage(const std::string& filename) : filename(filename) {
        }
        void display() const override {
        std::lock_guard<std::mutex>
          lock(cacheMutex);
          auto it = cache.find(filename);
          if (it != cache.end() &&
          !it->second.expired()) {
          std::cout <<
          "Using cached image: " << filename << std::endl;
          realImage = it->second.lock();
          } else {
          std::cout <<
          "Caching new image: " << filename << std::endl;
          realImage = std::make_shared<RealImage>
            (filename);
            cache[filename] = realImage;
            }
            realImage->
            display();
            }
            };
            std::unordered_map<std::string, std::weak_ptr<RealImage>> CachedProxyImage::cache;
              std::mutex CachedProxyImage::cacheMutex;
              // 访问控制代理
              class AuthProxy
              : public Image {
              private:
              std::unique_ptr<Image> target;
                std::string requiredRole;
                public:
                AuthProxy(std::unique_ptr<Image> img, const std::string& role)
                  : target(std::move(img)), requiredRole(role) {
                  }
                  void display() const override {
                  if (checkAccess()) {
                  target->
                  display();
                  } else {
                  std::cout <<
                  "Access denied: Requires role '" << requiredRole
                  <<
                  "', current role is '"
                  <<
                  SessionManager::getInstance()->
                  getSession().getRole()
                  <<
                  "'" << std::endl;
                  }
                  }
                  private:
                  bool checkAccess() const {
                  const auto& role = SessionManager::getInstance()->
                  getSession().getRole();
                  return role == requiredRole || role == "admin";
                  // 管理员可以访问所有资源
                  }
                  };
                  // 日志代理
                  class LoggingProxy
                  : public Image {
                  private:
                  std::unique_ptr<Image> target;
                    public:
                    explicit LoggingProxy(std::unique_ptr<Image> img) : target(std::move(img)) {
                      }
                      void display() const override {
                      std::cout <<
                      "[LOG] Display request for " <<
                      getFilename() << std::endl;
                      auto start = std::chrono::high_resolution_clock::now();
                      target->
                      display();
                      auto end = std::chrono::high_resolution_clock::now();
                      std::cout <<
                      "[LOG] Display completed in "
                      << std::chrono::duration_cast<std::chrono::milliseconds>
                        (end - start).count()
                        <<
                        "ms" << std::endl;
                        }
                        private:
                        std::string getFilename() const {
                        if (auto real = dynamic_cast<RealImage*>
                          (target.get())) {
                          return real->
                          getFilename();
                          }
                          return "unknown";
                          }
                          };
                          // 工厂类
                          class ImageFactory
                          {
                          public:
                          static std::shared_ptr<Image>
                            createProtectedImage(const std::string& filename,
                            const std::string& role) {
                            return std::make_shared<LoggingProxy>
                              (
                              std::make_unique<AuthProxy>
                                (
                                std::make_unique<CachedProxyImage>
                                  (filename),
                                  role
                                  )
                                  );
                                  }
                                  };
                                  // 客户端代码
                                  int main() {
                                  // 创建需要管理员权限的图片代理
                                  auto image = ImageFactory::createProtectedImage("sensitive.jpg", "admin");
                                  // 尝试以访客身份访问(会被拒绝)
                                  std::cout <<
                                  "=== Attempting to access as guest ===" << std::endl;
                                  image->
                                  display();
                                  // 登录为管理员
                                  SessionManager::getInstance()->
                                  loginAsAdmin();
                                  // 再次尝试访问(成功)
                                  std::cout <<
                                  "\n=== Logged in as admin, attempting access ===" << std::endl;
                                  image->
                                  display();
                                  // 再次请求同一图片(使用缓存)
                                  std::cout <<
                                  "\n=== Requesting same image again ===" << std::endl;
                                  image->
                                  display();
                                  // 创建普通用户可见的图片
                                  std::cout <<
                                  "\n=== Creating user-level image ===" << std::endl;
                                  auto userImage = ImageFactory::createProtectedImage("public.jpg", "user");
                                  // 管理员可以访问用户级资源
                                  userImage->
                                  display();
                                  // 登出
                                  SessionManager::getInstance()->
                                  logout();
                                  // 尝试再次访问(被拒绝)
                                  std::cout <<
                                  "\n=== Logged out, attempting access again ===" << std::endl;
                                  image->
                                  display();
                                  userImage->
                                  display();
                                  return 0;
                                  }
优化项
1. 内存管理优化(使用智能指针)
#include <memory>
  class ProxyImage
  : public Image {
  private:
  std::string filename;
  mutable std::unique_ptr<RealImage> realImage;
    // 智能指针自动管理内存
    public:
    explicit ProxyImage(const std::string& filename) : filename(filename) {
    }
    void display() const override {
    if (!realImage) {
    realImage = std::make_unique<RealImage>
      (filename);
      }
      realImage->
      display();
      }
      };

优点:避免内存泄漏,无需手动管理RealImage生命周期

2. 接口抽象与工厂模式
// 工厂类创建代理
class ImageFactory
{
public:
static std::shared_ptr<Image>
  createImage(const std::string& filename) {
  return std::make_shared<ProxyImage>
    (filename);
    }
    };
    // 客户端使用
    auto image = ImageFactory::createImage("test.jpg");

优点:解耦对象创建逻辑,支持未来扩展其他代理类型

3. 多线程安全(双重检查锁定)
void display() const override {
if (!realImage) {
std::lock_guard<std::mutex>
  lock(mutex);
  // 加锁
  if (!realImage) {
  // 双重检查
  realImage = std::make_unique<RealImage>
    (filename);
    }
    }
    realImage->
    display();
    }

优点:在多线程环境下保证RealImage只被创建一次

4. 缓存机制(扩展代理功能)
class CachedProxyImage
: public Image {
private:
std::string filename;
mutable std::shared_ptr<RealImage> realImage;
  static std::unordered_map<std::string, std::weak_ptr<RealImage>> cache;
    static std::mutex cacheMutex;
    public:
    explicit CachedProxyImage(const std::string& filename) : filename(filename) {
    }
    void display() const override {
    std::lock_guard<std::mutex>
      lock(cacheMutex);
      // 检查缓存
      auto it = cache.find(filename);
      if (it != cache.end() &&
      !it->second.expired()) {
      realImage = it->second.lock();
      } else {
      realImage = std::make_shared<RealImage>
        (filename);
        cache[filename] = realImage;
        }
        realImage->
        display();
        }
        };

优点:相同文件只加载一次,节省资源

5. 延迟加载策略(参数化控制)
class ConfigurableProxy
: public Image {
private:
std::string filename;
std::unique_ptr<RealImage> realImage;
  bool lazyLoad;
  public:
  explicit ConfigurableProxy(const std::string& filename, bool lazy = true)
  : filename(filename), lazyLoad(lazy) {
  }
  void display() const override {
  if (!realImage && lazyLoad) {
  realImage = std::make_unique<RealImage>
    (filename);
    }
    if (realImage) realImage->
    display();
    else std::cout <<
    "Image not loaded" << std::endl;
    }
    void forceLoad() {
    // 提供显式加载接口
    if (!realImage) {
    realImage = std::make_unique<RealImage>
      (filename);
      }
      }
      };

优点:支持灵活的加载策略配置

6. 日志记录(横切关注点)
class LoggingProxy
: public Image {
private:
std::unique_ptr<Image> target;
  public:
  explicit LoggingProxy(std::unique_ptr<Image> img) : target(std::move(img)) {
    }
    void display() const override {
    std::cout <<
    "[LOG] Display request for " <<
    getFilename() << std::endl;
    auto start = std::chrono::high_resolution_clock::now();
    target->
    display();
    auto end = std::chrono::high_resolution_clock::now();
    std::cout <<
    "[LOG] Display completed in "
    << std::chrono::duration_cast<std::chrono::milliseconds>
      (end - start).count()
      <<
      "ms" << std::endl;
      }
      private:
      std::string getFilename() const {
      // 通过dynamic_cast尝试获取文件名(需要在RealImage中暴露接口)
      if (auto real = dynamic_cast<RealImage*>
        (target.get())) {
        return real->
        getFilename();
        }
        return "unknown";
        }
        };

优点:非侵入式添加日志功能

7. 访问控制(保护代理)
class AuthProxy
: public Image {
private:
std::unique_ptr<Image> target;
  std::string requiredRole;
  public:
  AuthProxy(std::unique_ptr<Image> img, const std::string& role)
    : target(std::move(img)), requiredRole(role) {
    }
    void display() const override {
    if (checkAccess()) {
    target->
    display();
    } else {
    std::cout <<
    "Access denied: Requires role " << requiredRole << std::endl;
    }
    }
    private:
    bool checkAccess() const {
    // 实际实现中会检查当前用户角色
    // 这里简化为硬编码检查
    return UserSession::getCurrentRole() == requiredRole;
    }
    };

优点:实现细粒度的访问控制

8. 组合多种代理
// 客户端可以组合使用多种代理
auto image = std::make_unique<LoggingProxy>
  (
  std::make_unique<AuthProxy>
    (
    std::make_unique<ProxyImage>
      ("secret.jpg"),
      "admin"
      )
      );
      image->
      display();
      // 先验证权限,再记录日志,最后显示图片

优点:灵活组合不同功能的代理

四、与其他模式的区别

  1. 与装饰器模式的区别

    • 代理模式:重点在于控制对象的访问,客户端通常不知道真实对象的存在
    • 装饰器模式:重点在于动态增强对象的功能,客户端直接与装饰器交互
  2. 与适配器模式的区别

    • 代理模式:保持接口不变,提供相同功能但增加控制逻辑
    • 适配器模式:改变接口以适配不同的客户端需求
posted @ 2025-08-09 22:52  yfceshi  阅读(13)  评论(0)    收藏  举报