设计模式-代理模式

代理模式(Proxy Pattern)是一种结构型设计模式,通过引入代理对象控制对原始对象的访问,在不修改原始类的前提下增强其功能。代理模式的核心是间接访问,常用于权限控制、延迟加载、日志记录等场景。

核心思想

  • 中介隔离:代理对象作为客户端和真实对象之间的中介,管理对真实对象的访问。
  • 职责分离:将非核心逻辑(如权限校验、日志)从真实对象中剥离,提升代码可维护性。
  • 透明性:客户端无需感知代理存在,代理与真实对象实现相同接口。

模式结构

角色职责
抽象主题(Subject)定义真实对象和代理对象的共同接口,客户端依赖此接口
真实主题(Real Subject)实现核心业务逻辑的具体类,是代理最终调用的对象
代理(Proxy)实现抽象主题接口,持有真实主题的引用,负责预处理、过滤或后置处理请求

实现方式

1. 静态代理(手动编码代理类)
示例:文件访问保护代理

// 抽象主题
interface FileAccess {
    void readFile(String filename);
}

// 真实主题
class RealFileAccess implements FileAccess {
    @Override
    public void readFile(String filename) {
        System.out.println("读取文件内容:" + filename);
    }
}

// 代理类(添加权限校验)
class FileAccessProxy implements FileAccess {
    private RealFileAccess realFileAccess;
    private String userRole;

    public FileAccessProxy(String userRole) {
        this.userRole = userRole;
    }

    @Override
    public void readFile(String filename) {
        if (!"admin".equals(userRole)) {
            System.out.println("无权限访问文件!");
            return;
        }
        if (realFileAccess == null) {
            realFileAccess = new RealFileAccess(); // 延迟初始化
        }
        realFileAccess.readFile(filename);
    }
}

// 客户端
public class Client {
    public static void main(String[] args) {
        FileAccess proxy = new FileAccessProxy("user");
        proxy.readFile("secret.txt");  // 输出:无权限访问文件!
    }
}

2. 动态代理(运行时生成代理类)
JDK动态代理示例(基于接口)

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

// 抽象主题
interface Database {
    void query(String sql);
}

// 真实主题
class RealDatabase implements Database {
    @Override
    public void query(String sql) {
        System.out.println("执行查询:" + sql);
    }
}

// 代理处理器(添加日志)
class LoggingHandler implements InvocationHandler {
    private Object target;

    public LoggingHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("记录日志:执行方法 " + method.getName());
        return method.invoke(target, args);
    }
}

// 客户端
public class Client {
    public static void main(String[] args) {
        Database realDb = new RealDatabase();
        Database proxy = (Database) Proxy.newProxyInstance(
                realDb.getClass().getClassLoader(),
                realDb.getClass().getInterfaces(),
                new LoggingHandler(realDb)
        );
        proxy.query("SELECT * FROM users"); 
        // 输出:记录日志:执行方法 query → 执行查询:SELECT * FROM users
    }
}

CGLIB动态代理示例(基于类,无需接口)

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

class UserService {
    public void save() {
        System.out.println("保存用户数据");
    }
}

class TransactionInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("开启事务");
        Object result = proxy.invokeSuper(obj, args);
        System.out.println("提交事务");
        return result;
    }
}

public class Client {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(UserService.class);
        enhancer.setCallback(new TransactionInterceptor());
        UserService proxy = (UserService) enhancer.create();
        proxy.save(); 
        // 输出:开启事务 → 保存用户数据 → 提交事务
    }
}

代理模式变体

代理类型特点
远程代理隐藏远程对象通信细节(如HTTP/RPC调用),客户端像调用本地对象一样操作
虚拟代理延迟大对象的创建,直到真正需要时(如图片加载、大文件处理)
保护代理控制访问权限,根据身份决定是否允许操作
缓存代理缓存请求结果,减少重复计算或网络请求
同步代理为多线程环境提供线程安全访问控制

优缺点分析

优点

  • 职责清晰:分离核心功能与非核心逻辑(如安全、日志)。
  • 高扩展性:通过代理类灵活增强功能,符合开闭原则。
  • 保护真实对象:限制直接访问,提升系统安全性。

缺点

  • 增加系统复杂度:引入代理层可能使代码结构复杂化。
  • 性能损耗:动态代理通过反射实现,调用速度较慢(可通过缓存优化)。
  • 静态代理类冗余:需为每个真实类编写代理类,代码量大。

应用场景

适用场景

  • 远程代理:为远程服务(如RPC接口)提供本地代理,隐藏网络通信细节。
  • 虚拟代理:延迟高开销对象的创建(如图片懒加载)。
  • 保护代理:控制对敏感对象的访问权限。
  • 智能引用代理:添加额外操作(如引用计数、对象状态监控)。
  • 缓存代理:缓存请求结果,减少重复计算或网络开销。

实际应用

  • Spring AOP:通过动态代理实现日志、事务等切面功能。
  • MyBatis Mapper接口:动态代理生成数据库操作实现类。
  • RPC框架(如Dubbo):客户端通过代理调用远程服务。
  • Hibernate延迟加载:虚拟代理延迟数据库查询。
  • Java安全管理器:保护代理控制对系统资源的访问。

与其他模式对比

模式对比点
装饰器模式关注增强功能,透明性更高;代理模式强调访问控制,可能隐藏真实对象
适配器模式解决接口不兼容问题;代理模式保持接口一致,仅控制访问流程
外观模式封装多个子系统简化接口;代理模式控制单个对象的访问

使用建议

  • 优先选择动态代理:减少重复代码,但需注意性能影响。
  • 明确代理职责:避免代理类承担过多无关逻辑,保持单一职责。
  • 结合其他模式:如与工厂模式结合管理代理对象创建。

总结

代理模式通过间接访问机制,在保护真实对象的同时扩展其能力,是系统解耦和功能增强的常用手段。在需要控制访问权限、优化资源使用或添加横切关注点(如日志、事务)的场景中,合理运用代理模式能显著提升代码的灵活性和可维护性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小九没绝活

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值