【设计模式】代理模式

简介

假设你在网上购物时,快递员无法直接将包裹送到你手中(比如你不在家)。

代理模式的解决方案是:

快递员将包裹交给小区代收点(代理),代收点代替你控制和管理包裹的访问。

代收点可以添加额外功能:比如验证你的身份、暂存包裹直到你有空取件。

你最终通过代收点间接拿到包裹,整个过程保护了你的隐私和便利性。

适用场景

远程代理:访问远程对象(如网络服务调用)。

虚拟代理:延迟创建开销大的对象(如图片懒加载)。

保护代理:控制权限(如接口访问权限验证)。

日志代理:记录方法调用信息(如监控系统)。

优点

隔离目标对象与客户端,增强安全性。

在不修改目标对象的前提下扩展功能。

缺点

增加代码复杂度(需额外代理类)。

可能降低系统响应速度(代理层处理逻辑)。

类图

代码

java 复制代码
// 抽象主题:用户网购行为
interface Shopping {
void receivePackage(String packageName);
}


// 真实主题:快递直接送货
class CourierDelivery implements Shopping {
@Override
public void receivePackage(String packageName) {
System.out.println("快递员已将包裹[" + packageName + "]送到用户手中!");
}
}


// 代理类:代收点暂存包裹
class ParcelLockerProxy implements Shopping {
private Shopping courier;
private String pendingPackage;


public ParcelLockerProxy() {
this.courier = new CourierDelivery();
}


@Override
public void receivePackage(String packageName) {
// 代理控制访问:暂存包裹,延迟通知用户
System.out.println("代收点暂存包裹[" + packageName + "],等待用户取件");
this.pendingPackage = packageName;
notifyUser();
}


private void notifyUser() {
// 模拟延迟通知
System.out.println("短信通知:您的包裹已到代收点,请及时领取!");
}
}


// 客户端
public class ProxyDemo {
public static void main(String[] args) {
// 直接访问真实对象
Shopping courier = new CourierDelivery();
courier.receivePackage("手机");


// 通过代理访问
Shopping proxy = new ParcelLockerProxy();
proxy.receivePackage("电脑");
}
}

实际场景

Spring 框架使用动态代理实现面向切面编程(AOP),例如事务管理,日志代理。

java 复制代码
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;


// 接口:用户服务
interface UserService {
void addUser(String name);
}


// 真实主题:用户服务实现
class UserServiceImpl implements UserService {
@Override
public void addUser(String name) {
System.out.println("添加用户: " + name);
}
}


// 动态代理:日志增强
class LoggingProxy implements InvocationHandler {
private Object target;


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


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


// 客户端
public class DynamicProxyDemo {
public static void main(String[] args) {
UserService realService = new UserServiceImpl();
UserService proxy = (UserService) Proxy.newProxyInstance(
realService.getClass().getClassLoader(),
realService.getClass().getInterfaces(),
new LoggingProxy(realService)
);


proxy.addUser("张三");
}
}
相关推荐
AI人工智能+电脑小能手8 小时前
大白话说Java设计模式-23-桥接模式(源码剖析篇)
java·设计模式·jdbc·桥接模式·源码分析·awt·java logging
嘟嘟071711 小时前
TypeScript 工具类型通关:Pick、Omit、Partial、Record 区别与 Omit 等价实现一次讲清
设计模式·面试·typescript
SL_staff11 小时前
中小离散制造如何用工艺路线模板解决‘人走流程丢’——JVS-APS 实践解析
java·设计模式·全栈
Asize11 小时前
3 种设计模式 + DI:Nest.js 后端第一课
后端·设计模式·nestjs
St_rive21 小时前
Page Object设计模式
java·开发语言·设计模式
Lam Tang1 天前
APS 系列文章10
java·代理模式
Lam Tang1 天前
APS 系列文章 08
java·代理模式
wangjialelele1 天前
动态规划DP经典题型总结(Java、C++):路径、子数组、子序列、背包问题详解
java·c++·算法·面试·动态规划·代理模式
聪明蛋子哟1 天前
从MCP到A2A再到Proxy:Agent-工具协议的三种代理模式
代理模式
烬羽1 天前
NestJS 依赖注入:Controller 里那个没有 new 的 service,到底从哪来的?
设计模式·typescript·nestjs