代理模式什么是代理模式代理模式(Proxy Pattern)是一种结构型设计模式,它为其他对象提供一种代理以控制对这个对象的访问。代理模式可以在客户端和目标对象之间起到中介的作用,并且可以添加额外的功能。

代理模式的核心思想是:

为其他对象提供一种代理以控制对这个对象的访问在客户端和目标对象之间起到中介的作用可以在不改变目标对象的情况下增加额外的功能为什么需要代理模式在实际开发中,我们经常需要在访问对象时添加一些额外的控制逻辑,比如:

延迟加载(懒加载)访问控制(权限检查)日志记录远程代理智能引用代理模式通过创建一个代理对象来控制对真实对象的访问,可以在不修改真实对象的情况下添加这些额外的功能。

代理模式的结构代理模式包含以下几个角色:

抽象主题(Subject):声明了真实主题和代理主题的共同接口真实主题(RealSubject):定义了代理主题所代表的真实对象代理主题(Proxy):保存一个引用使得代理可以访问实体,并提供一个与Subject的接口相同的接口代理模式的实现基本实现// 抽象主题接口

interface Subject {

void request();

}

// 真实主题

class RealSubject implements Subject {

@Override

public void request() {

System.out.println("真实主题处理请求");

}

}

// 代理主题

class Proxy implements Subject {

private RealSubject realSubject;

@Override

public void request() {

if (realSubject == null) {

realSubject = new RealSubject();

}

preRequest();

realSubject.request();

postRequest();

}

private void preRequest() {

System.out.println("代理前置处理");

}

private void postRequest() {

System.out.println("代理后置处理");

}

}

// 使用示例

public class ProxyDemo {

public static void main(String[] args) {

Subject subject = new Proxy();

subject.request();

}

}实际应用示例// 图片加载示例

// 图片接口

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("从磁盘加载图片: " + filename);

// 模拟加载时间

try {

Thread.sleep(1000);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

@Override

public void display() {

System.out.println("显示图片: " + filename);

}

}

// 图片代理类

class ProxyImage implements Image {

private RealImage realImage;

private String filename;

public ProxyImage(String filename) {

this.filename = filename;

}

@Override

public void display() {

if (realImage == null) {

realImage = new RealImage(filename);

}

realImage.display();

}

}

// 使用示例

public class ImageProxyDemo {

public static void main(String[] args) {

Image image1 = new ProxyImage("photo1.jpg");

Image image2 = new ProxyImage("photo2.jpg");

// 第一次显示图片,会加载

System.out.println("第一次显示图片1:");

image1.display();

System.out.println();

// 第二次显示图片,不会重新加载

System.out.println("第二次显示图片1:");

image1.display();

System.out.println();

// 显示图片2

System.out.println("显示图片2:");

image2.display();

}

}代理模式的应用场景远程代理:为一个位于不同的地址空间的对象提供一个本地的代表对象虚拟代理:根据需要创建开销很大的对象,通过它来存放实例化需要很长时间的真实对象保护代理:控制对原始对象的访问,保护代理用于对象应该有不同的访问权限的时候智能引用:取代了简单的指针,它在访问对象时执行一些附加操作防火墙代理:保护目标不让恶意用户接近同步代理:在多线程应用中为主题提供安全的访问代理模式的优缺点优点职责清晰:真实的角色就是实现实际的业务逻辑,不用关心其他非本职责的事务代理对象可以在客户端和目标对象之间起到中介的作用:保护目标对象高扩展性:代理模式符合开闭原则,可以在不修改目标对象的情况下增加新的功能智能化:代理可以在运行时动态地添加或删除功能缺点增加系统复杂度:由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢实现代理模式需要额外的工作:有些代理模式的实现非常复杂代理模式的类型1. 静态代理// 静态代理示例

// 用户服务接口

interface UserService {

void addUser(String username);

void deleteUser(String username);

String getUser(String username);

}

// 真实用户服务

class RealUserService implements UserService {

@Override

public void addUser(String username) {

System.out.println("添加用户: " + username);

}

@Override

public void deleteUser(String username) {

System.out.println("删除用户: " + username);

}

@Override

public String getUser(String username) {

System.out.println("获取用户: " + username);

return "用户信息: " + username;

}

}

// 用户服务代理

class UserServiceProxy implements UserService {

private UserService userService;

private String currentUser;

public UserServiceProxy(UserService userService, String currentUser) {

this.userService = userService;

this.currentUser = currentUser;

}

@Override

public void addUser(String username) {

if (hasPermission("add")) {

userService.addUser(username);

} else {

System.out.println("权限不足,无法添加用户");

}

}

@Override

public void deleteUser(String username) {

if (hasPermission("delete")) {

userService.deleteUser(username);

} else {

System.out.println("权限不足,无法删除用户");

}

}

@Override

public String getUser(String username) {

if (hasPermission("read")) {

return userService.getUser(username);

} else {

System.out.println("权限不足,无法获取用户信息");

return null;

}

}

private boolean hasPermission(String operation) {

// 简化的权限检查

System.out.println("检查用户 " + currentUser + " 的 " + operation + " 权限");

return true; // 简化实现

}

}

// 使用示例

public class StaticProxyDemo {

public static void main(String[] args) {

UserService realService = new RealUserService();

UserService proxyService = new UserServiceProxy(realService, "admin");

proxyService.addUser("张三");

proxyService.deleteUser("李四");

String user = proxyService.getUser("王五");

System.out.println(user);

}

}2. 动态代理import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

import java.lang.reflect.Proxy;

// 动态代理示例

// 日志处理类

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());

long startTime = System.currentTimeMillis();

Object result = method.invoke(target, args);

long endTime = System.currentTimeMillis();

System.out.println("方法执行完成: " + method.getName() +

", 耗时: " + (endTime - startTime) + "ms");

return result;

}

}

// 计算器接口

interface Calculator {

int add(int a, int b);

int subtract(int a, int b);

int multiply(int a, int b);

double divide(int a, int b);

}

// 计算器实现

class CalculatorImpl implements Calculator {

@Override

public int add(int a, int b) {

// 模拟计算时间

try {

Thread.sleep(100);

} catch (InterruptedException e) {

e.printStackTrace();

}

return a + b;

}

@Override

public int subtract(int a, int b) {

return a - b;

}

@Override

public int multiply(int a, int b) {

return a * b;

}

@Override

public double divide(int a, int b) {

if (b == 0) {

throw new IllegalArgumentException("除数不能为0");

}

return (double) a / b;

}

}

// 动态代理工厂

class ProxyFactory {

public static T createProxy(T target, Class interfaceClass) {

return (T) Proxy.newProxyInstance(

target.getClass().getClassLoader(),

new Class[]{interfaceClass},

new LoggingHandler(target)

);

}

}

// 使用示例

public class DynamicProxyDemo {

public static void main(String[] args) {

Calculator calculator = new CalculatorImpl();

Calculator proxyCalculator = ProxyFactory.createProxy(calculator, Calculator.class);

System.out.println("10 + 5 = " + proxyCalculator.add(10, 5));

System.out.println("10 - 5 = " + proxyCalculator.subtract(10, 5));

System.out.println("10 * 5 = " + proxyCalculator.multiply(10, 5));

System.out.println("10 / 5 = " + proxyCalculator.divide(10, 5));

}

}代理模式与其他模式的比较与适配器模式的区别代理模式:不改变接口,但控制对对象的访问适配器模式:改变接口以匹配客户端需求与装饰器模式的区别代理模式:控制对对象的访问装饰器模式:动态地给对象添加职责与外观模式的区别代理模式:为一个对象提供代理外观模式:为一组对象提供统一接口实际项目中的应用// 数据库连接代理示例

// 数据库连接接口

interface DatabaseConnection {

void connect();

void executeQuery(String sql);

void close();

boolean isConnected();

}

// 真实数据库连接

class RealDatabaseConnection implements DatabaseConnection {

private String url;

private boolean connected = false;

public RealDatabaseConnection(String url) {

this.url = url;

}

@Override

public void connect() {

System.out.println("连接到数据库: " + url);

// 模拟连接过程

try {

Thread.sleep(500);

} catch (InterruptedException e) {

e.printStackTrace();

}

connected = true;

System.out.println("数据库连接成功");

}

@Override

public void executeQuery(String sql) {

if (!connected) {

throw new IllegalStateException("数据库未连接");

}

System.out.println("执行SQL查询: " + sql);

// 模拟查询过程

try {

Thread.sleep(200);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println("查询执行完成");

}

@Override

public void close() {

if (connected) {

System.out.println("关闭数据库连接");

connected = false;

}

}

@Override

public boolean isConnected() {

return connected;

}

}

// 数据库连接代理

class DatabaseConnectionProxy implements DatabaseConnection {

private RealDatabaseConnection realConnection;

private String url;

private long lastAccessTime;

private static final long TIMEOUT = 30000; // 30秒超时

public DatabaseConnectionProxy(String url) {

this.url = url;

}

@Override

public void connect() {

if (realConnection == null) {

realConnection = new RealDatabaseConnection(url);

}

realConnection.connect();

lastAccessTime = System.currentTimeMillis();

}

@Override

public void executeQuery(String sql) {

checkConnection();

logQuery(sql);

realConnection.executeQuery(sql);

lastAccessTime = System.currentTimeMillis();

}

@Override

public void close() {

if (realConnection != null) {

realConnection.close();

}

}

@Override

public boolean isConnected() {

if (realConnection == null) {

return false;

}

// 检查是否超时

if (System.currentTimeMillis() - lastAccessTime > TIMEOUT) {

System.out.println("连接超时,自动断开");

realConnection.close();

return false;

}

return realConnection.isConnected();

}

private void checkConnection() {

if (realConnection == null || !realConnection.isConnected()) {

connect();

}

// 检查超时

if (System.currentTimeMillis() - lastAccessTime > TIMEOUT) {

System.out.println("连接超时,重新连接");

realConnection.close();

connect();

}

}

private void logQuery(String sql) {

System.out.println("[" + new java.util.Date() + "] 执行查询: " + sql);

}

}

// 使用示例

public class DatabaseProxyDemo {

public static void main(String[] args) throws InterruptedException {

DatabaseConnection connection = new DatabaseConnectionProxy("jdbc:mysql://localhost:3306/test");

// 执行查询

connection.executeQuery("SELECT * FROM users");

// 等待一段时间

System.out.println("等待1秒...");

Thread.sleep(1000);

// 再次执行查询

connection.executeQuery("SELECT * FROM orders");

// 检查连接状态

System.out.println("连接状态: " + connection.isConnected());

// 关闭连接

connection.close();

}

}// Spring AOP代理示例

// 模拟Spring AOP的实现

interface BusinessService {

void doBusiness();

String getResult();

}

class BusinessServiceImpl implements BusinessService {

@Override

public void doBusiness() {

System.out.println("执行业务逻辑");

// 模拟业务处理时间

try {

Thread.sleep(300);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

@Override

public String getResult() {

return "业务处理结果";

}

}

// AOP切面接口

interface Aspect {

void before();

void after();

void afterReturning(Object result);

void afterThrowing(Exception ex);

}

// 日志切面

class LoggingAspect implements Aspect {

@Override

public void before() {

System.out.println("[日志] 方法开始执行");

}

@Override

public void after() {

System.out.println("[日志] 方法执行完成");

}

@Override

public void afterReturning(Object result) {

System.out.println("[日志] 方法返回: " + result);

}

@Override

public void afterThrowing(Exception ex) {

System.out.println("[日志] 方法抛出异常: " + ex.getMessage());

}

}

// 性能监控切面

class PerformanceAspect implements Aspect {

private long startTime;

@Override

public void before() {

startTime = System.currentTimeMillis();

System.out.println("[性能] 开始计时");

}

@Override

public void after() {

long endTime = System.currentTimeMillis();

System.out.println("[性能] 执行耗时: " + (endTime - startTime) + "ms");

}

@Override

public void afterReturning(Object result) {

// 空实现

}

@Override

public void afterThrowing(Exception ex) {

// 空实现

}

}

// AOP代理

class AopProxy implements BusinessService {

private BusinessService target;

private List aspects;

public AopProxy(BusinessService target, List aspects) {

this.target = target;

this.aspects = aspects;

}

@Override

public void doBusiness() {

// 执行前置通知

for (Aspect aspect : aspects) {

aspect.before();

}

try {

target.doBusiness();

// 执行后置通知

for (Aspect aspect : aspects) {

aspect.after();

}

} catch (Exception e) {

// 执行异常通知

for (Aspect aspect : aspects) {

aspect.afterThrowing(e);

}

}

}

@Override

public String getResult() {

Object result = null;

Exception exception = null;

// 执行前置通知

for (Aspect aspect : aspects) {

aspect.before();

}

try {

result = target.getResult();

// 执行后置通知

for (Aspect aspect : aspects) {

aspect.after();

}

// 执行返回通知

for (Aspect aspect : aspects) {

aspect.afterReturning(result);

}

} catch (Exception e) {

exception = e;

// 执行异常通知

for (Aspect aspect : aspects) {

aspect.afterThrowing(e);

}

}

if (exception != null) {

throw new RuntimeException(exception);

}

return (String) result;

}

}

// 使用示例

public class AopProxyDemo {

public static void main(String[] args) {

BusinessService realService = new BusinessServiceImpl();

// 创建切面

List aspects = new ArrayList<>();

aspects.add(new LoggingAspect());

aspects.add(new PerformanceAspect());

// 创建代理

BusinessService proxyService = new AopProxy(realService, aspects);

// 通过代理执行业务

proxyService.doBusiness();

System.out.println();

String result = proxyService.getResult();

System.out.println("获取结果: " + result);

}

}总结代理模式是一种非常实用的结构型设计模式,它通过创建代理对象来控制对真实对象的访问,可以在不修改真实对象的情况下添加额外的功能。在实际开发中,当我们需要在访问对象时添加控制逻辑时,代理模式是一个很好的选择。

使用代理模式的关键点:

识别出需要添加控制逻辑的对象定义抽象主题接口创建真实主题实现具体业务逻辑创建代理主题来控制对真实主题的访问客户端通过代理主题与真实主题交互代理模式的优点是可以添加额外的控制逻辑,符合开闭原则,但也需要注意可能会增加系统复杂度和请求处理时间。在现代Java开发中,代理模式广泛应用于Spring AOP、数据库连接池、远程方法调用、图像加载等场景。