设计模式 - 结构型 - 代理模式(Proxy Pattern)

代理模式(Proxy Pattern)是一种结构型设计模式,通过引入代理对象控制对目标对象的访问,在请求处理前后插入附加逻辑(如缓存、权限校验、延迟加载等),同时保持客户端与目标对象的解耦。以下是该模式的系统性解析:


一、核心定义与设计目标

  1. 定义
    代理模式通过代理对象替代目标对象,提供与目标对象相同的接口,客户端通过代理间接访问目标,从而实现对目标对象的访问控制与功能增强。例如,明星经纪人作为代理控制艺人的工作安排。

  2. 设计目标

    • 访问控制:限制或保护对敏感对象的直接访问(如数据库连接)。
    • 功能增强:在不修改目标对象的前提下扩展功能(如日志记录、性能监控)。
    • 延迟初始化:按需创建资源密集型对象(如大文件加载)。

二、模式结构与角色划分

  1. 核心角色

    • 抽象主题(Subject):定义代理与目标对象的公共接口(如 Cache 接口)。
    • 真实主题(Real Subject):实现核心业务逻辑的具体对象(如 JvmCache)。
    • 代理类(Proxy):持有目标对象的引用,实现附加逻辑并调用目标方法(如 RedisCacheDecorator)。
  2. UML类图示例

+-------------------+           +---------------------------+
|   Subject         |<|-------|>|   Proxy                   |
| +request()        |           | -realSubject: RealSubject |
+-------------------+           +---------------------------+
       ▲                              ▲
       |                              |
+-------------------+          +-------------------+
| RealSubject       |          | Client            |
+-------------------+          +-------------------+
  1. 实现方式
    • 静态代理:手动编写代理类,编译时生成(简单但类数量多)。
    • 动态代理:运行时动态生成代理类,分为两类:
      • JDK动态代理:基于接口,通过 InvocationHandler 实现。
      • CGLib动态代理:基于继承,生成目标类的子类(无需接口)。

三、优缺点分析

优点
  1. 解耦性:客户端仅依赖抽象接口,与目标对象实现解耦。
  2. 灵活性:动态扩展功能,符合开闭原则。
  3. 性能优化:通过延迟加载降低系统初始化开销。
缺点
  1. 类膨胀:静态代理需手动编写多个代理类。
  2. 性能损耗:动态代理的反射调用可能增加耗时。
  3. 复杂性:需明确代理逻辑的边界,避免过度设计。

四、适用场景

  1. 远程代理
    • 访问分布式服务(如RPC框架)。
  2. 虚拟代理
    • 延迟加载大资源(如图片、视频)。
  3. 保护代理
    • 权限校验(如数据库访问控制)。
  4. 智能引用
    • 缓存结果、日志记录、性能监控。

五、实现示例(Java)

以多级缓存系统为例,演示动态代理的应用:

// 抽象主题:缓存接口
interface Cache {
    Object get(String key);
    void put(String key, Object value);
}

// 真实主题:本地缓存
class LocalCache implements Cache {
    private Map<String, Object> store = new HashMap<>();
    @Override public Object get(String key) { return store.get(key); }
    @Override public void put(String key, Object value) { store.put(key, value); }
}

// 动态代理增强类(JDK方式)
class CacheInvocationHandler implements InvocationHandler {
    private Cache target;
    public CacheInvocationHandler(Cache target) { this.target = target; }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (method.getName().equals("get")) {
            Object result = method.invoke(target, args);
            if (result == null) {
                result = fetchFromRemote((String) args[0]); // 模拟远程加载
                target.put((String) args[0], result);
            }
            return result;
        }
        return method.invoke(target, args);
    }
    private Object fetchFromRemote(String key) { return "Remote Data: " + key; }
}

// 客户端调用
public class Client {
    public static void main(String[] args) {
        Cache proxy = (Cache) Proxy.newProxyInstance(
            Cache.class.getClassLoader(),
            new Class[]{Cache.class},
            new CacheInvocationHandler(new LocalCache())
        );
        System.out.println(proxy.get("user_1001")); // 输出:Remote Data: user_1001
    }
}

六、实际应用案例

  1. Java IO流
    • BufferedInputStream 代理 FileInputStream 实现缓冲功能。
  2. Spring AOP
    • 通过动态代理实现事务管理与日志切面。
  3. RPC框架
    • 客户端代理远程服务接口,屏蔽网络通信细节。

七、与其他模式的对比

模式核心差异
适配器模式解决接口不兼容问题,而非功能扩展
装饰器模式侧重叠加功能,代理侧重访问控制
外观模式封装子系统简化接口,代理控制单个对象

八、总结

代理模式通过中介隔离逻辑增强,为对象访问提供了灵活可控的解决方案。其核心价值在于平衡功能扩展与代码维护性,尤其适用于需要动态控制访问或延迟加载资源的场景。开发中需根据需求选择代理类型(静态/动态),避免过度设计导致系统复杂度失控。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值