Skip to content

代理模式

引言

在软件系统中,当直接访问对象可能导致安全风险(如权限控制)、性能损耗(如大文件加载)或功能限制(如远程调用)时,代理模式应运而生。它通过创建代理对象作为原对象的替身,实现对目标对象的访问控制,成为系统设计中不可或缺的"守门人"。

诞生背景

GoF在《设计模式》中提出代理模式,解决三大核心问题:

  • 访问控制:限制敏感资源的直接访问(如数据库连接)
  • 性能优化:延迟高成本对象的创建(如图片懒加载)
  • 远程交互:为分布式对象提供本地代理(如RPC调用)

演进过程

  • 静态代理(1994):手动创建代理类,实现硬编码控制
  • 动态代理革命:Java反射/CGLib实现运行时动态代理
  • 现代应用:Spring AOP面向切面编程的核心实现机制
  • 云原生演进:服务网格(如Istio)中的透明代理架构

核心概念

  • 抽象主题(Subject):定义真实对象和代理对象的共用接口
  • 真实主题(Real Subject):实际执行业务逻辑的核心对象
  • 代理(Proxy):控制对真实主题的访问,可添加额外功能

通用实现

Java 实现(静态代理)

java
// 抽象主题
interface Image {
    void display();
}

// 真实主题
class RealImage implements Image {
    private String filename;
    
    public RealImage(String filename) {
        this.filename = filename;
        loadFromDisk();
    }
    
    private void loadFromDisk() {
        System.out.println("Loading image: " + filename);
    }
    
    public void display() {
        System.out.println("Displaying: " + filename);
    }
}

// 代理类
class ProxyImage implements Image {
    private RealImage realImage;
    private String filename;
    
    public ProxyImage(String filename) {
        this.filename = filename;
    }
    
    public void display() {
        if (realImage == null) {
            realImage = new RealImage(filename); // 延迟加载
        }
        realImage.display();
    }
}

// 客户端
public class Client {
    public static void main(String[] args) {
        Image image = new ProxyImage("high_res.jpg");
        // 图片尚未加载
        image.display(); // 首次访问时加载并显示
    }
}

PHP 实现(动态代理)

php
// 抽象主题
interface PaymentService {
    public function pay(int $amount): void;
}

// 真实主题
class RealPayment implements PaymentService {
    public function pay(int $amount): void {
        echo "Processing payment: $amount USD\n";
    }
}

// 代理处理器
class PaymentProxy implements \InvocationHandler {
    private $target;
    
    public function __construct(PaymentService $target) {
        $this->target = $target;
    }
    
    public function __call($method, $args) {
        if ($method === 'pay') {
            $this->preProcess($args[0]);
            call_user_func_array([$this->target, $method], $args);
            $this->postProcess();
        }
    }
    
    private function preProcess(int $amount): void {
        echo "[Security] Verifying transaction...\n";
    }
    
    private function postProcess(): void {
        echo "[Log] Payment recorded in audit trail\n";
    }
}

// 客户端
$realPayment = new RealPayment();
$proxy = new PaymentProxy($realPayment);
$proxy->pay(100); // 通过代理执行

应用场景

  • 虚拟代理:延迟大资源加载(如图片/视频)
  • 保护代理:控制敏感资源访问权限
  • 远程代理:为远程对象提供本地代表(如RPC)
  • 智能引用:添加额外操作(引用计数/日志记录)
  • 缓存代理:为高成本运算提供结果缓存

案例:文档访问控制系统

Java 实现(保护代理)

java
// 抽象主题
interface Document {
    void view();
}

// 真实主题
class SensitiveDocument implements Document {
    public void view() {
        System.out.println("Displaying classified content");
    }
}

// 保护代理
class DocumentProxy implements Document {
    private SensitiveDocument doc;
    private String userRole;
    
    public DocumentProxy(String userRole) {
        this.userRole = userRole;
    }
    
    public void view() {
        if (checkAccess()) {
            if (doc == null) {
                doc = new SensitiveDocument();
            }
            doc.view();
        } else {
            System.out.println("Access denied: Insufficient privileges");
        }
    }
    
    private boolean checkAccess() {
        return "admin".equals(userRole);
    }
}

// 客户端
public class Client {
    public static void main(String[] args) {
        Document userDoc = new DocumentProxy("guest");
        userDoc.view(); // Access denied
        
        Document adminDoc = new DocumentProxy("admin");
        adminDoc.view(); // Displaying classified content
    }
}

PHP 实现(缓存代理)

php
// 抽象主题
interface DataFetcher {
    public function fetchData(string $key): string;
}

// 真实主题
class DatabaseFetcher implements DataFetcher {
    public function fetchData(string $key): string {
        echo "Executing expensive database query...\n";
        // 模拟耗时操作
        sleep(2);
        return "Data for: $key";
    }
}

// 缓存代理
class CachingProxy implements DataFetcher {
    private $fetcher;
    private $cache = [];
    
    public function __construct(DataFetcher $fetcher) {
        $this->fetcher = $fetcher;
    }
    
    public function fetchData(string $key): string {
        if (!isset($this->cache[$key])) {
            $this->cache[$key] = $this->fetcher->fetchData($key);
        }
        return "[Cached] " . $this->cache[$key];
    }
}

// 客户端
$realFetcher = new DatabaseFetcher();
$proxy = new CachingProxy($realFetcher);

echo $proxy->fetchData("user_123") . "\n"; // 首次查询数据库
echo $proxy->fetchData("user_123") . "\n"; // 返回缓存结果

优点

  • 访问控制:精细化权限管理
  • 性能优化:延迟加载/缓存提升响应速度
  • 开闭原则:新增代理不影响现有代码
  • 职责清晰:分离核心逻辑与辅助功能

缺点

  • 响应延迟:代理层增加额外调用开销
  • 复杂度增加:需维护额外代理类
  • 层级嵌套:多层代理可能导致调试困难

扩展

  1. 动态代理
  • Java: InvocationHandler + Proxy.newProxyInstance()
  • PHP: __call()魔术方法实现动态拦截
  1. 虚拟代理集群
  • 管理分布式对象的代理池(如数据库连接池)
  1. 智能代理链
  • 组合多个代理形成处理流水线(缓存→验证→日志)

模式协作

  • 与装饰器模式:代理控制访问,装饰器增强功能(两者结构相似但目的不同)
  • 与适配器模式:代理使用相同接口,适配器转换不同接口
  • 与外观模式:代理控制单个对象,外观封装整个子系统
  • 与观察者模式:代理可触发状态变更通知(如缓存失效事件)

延伸思考

  • 微服务架构:Service Mesh中Envoy代理实现服务间安全通信
  • 前端性能优化:图片懒加载代理(IntersectionObserver API)
  • 区块链应用:智能合约作为资产交易的代理中介
  • 安全边界:API网关作为微服务的保护代理(鉴权/限流)

总结

代理模式是对象访问控制的精密阀门,通过代理对象对真实对象的访问进行拦截和管控。其核心价值在于:安全防护的守门人性能优化的调度师远程交互的本地大使。在现代分布式系统、高性能应用和安全敏感场景中,代理模式展现出不可替代的作用,成为构建健壮软件架构的关键模式。