DukeDuke
主页
关于我们
主页
关于我们
  • Java

    • Java基础

      • 内存与磁盘
      • 进制转换
      • 数据存储
      • Java基本数据类型
      • HashMap
      • Java四大引用
    • JVM

      • 认识JVM
      • JVM类加载器
      • 运行时数据区
      • 执行引擎
      • 本地方法接口
      • 本地方法库
      • JVM垃圾回收
      • JVM性能监控
      • JVM调优
    • 设计模式
      • 单例模式
      • 工厂模式
      • 策略模式
      • 适配器模式
      • 建造者模式
      • 原型模式
      • 装饰器模式
      • 代理模式
      • 外观模式
      • 享元模式
      • 组合模式
      • 桥接模式
    • Java多线程

      • Java 线程基础详解
      • Java 线程池详解
      • Java ThreadLocal 详解
      • Java volatile 详解
      • Java 线程间通信详解
      • Java 线程安全详解
      • Java 线程调度详解
      • Java 线程优先级详解

      • Java 线程中断详解
      • Java 线程死锁详解
    • Java反射
    • Java 面试题

      • Java 基础概念面试题
      • Java 面向对象编程面试题
      • Java 集合框架面试题
      • Java 多线程与并发面试题
      • JVM 与内存管理面试题
      • Java I/O 与 NIO 面试题
      • Java 异常处理面试题
      • Java 反射与注解面试题
      • Java Spring 框架面试题
      • Java 数据库与 JDBC 面试题
      • Java 性能优化面试题
      • Java 实际项目经验面试题
      • Java 高级特性面试题
      • Java 面试准备建议

代理模式

什么是代理模式?

代理模式就像请一个"替身"来帮你做事。想象一下,你想买房子,但你没有时间去看房,于是就请了一个房产中介(代理)来帮你找房子、看房子、谈价格。这个中介就是你的"代理",他代表你去做这些事情。

在编程中,代理模式就是创建一个代理对象来控制对另一个对象的访问。代理对象可以在访问真实对象之前或之后添加一些额外的处理逻辑。

代理模式的三种类型

1. 静态代理

静态代理是在编译时就确定代理关系的代理模式。

2. 动态代理

动态代理是在运行时动态创建代理对象的代理模式。

3. 虚拟代理

虚拟代理用于延迟加载,只有在真正需要时才创建真实对象。

示例一:房产中介代理(静态代理)

// 1. 定义接口
interface HouseService {
    void findHouse();
    void negotiatePrice();
    void signContract();
}

// 2. 真实对象(房主)
class HouseOwner implements HouseService {
    @Override
    public void findHouse() {
        System.out.println("房主:我的房子在市中心,3室2厅,120平米");
    }

    @Override
    public void negotiatePrice() {
        System.out.println("房主:最低价格200万,不能再低了");
    }

    @Override
    public void signContract() {
        System.out.println("房主:好的,我们签合同吧");
    }
}

// 3. 代理对象(房产中介)
class HouseAgent implements HouseService {
    private HouseOwner houseOwner;

    public HouseAgent() {
        this.houseOwner = new HouseOwner();
    }

    @Override
    public void findHouse() {
        System.out.println("中介:我来帮您找房子");
        houseOwner.findHouse();
        System.out.println("中介:这个房子位置很好,价格合理");
    }

    @Override
    public void negotiatePrice() {
        System.out.println("中介:我来帮您谈价格");
        houseOwner.negotiatePrice();
        System.out.println("中介:经过我的努力,价格可以再优惠5万");
    }

    @Override
    public void signContract() {
        System.out.println("中介:我来帮您办理签约手续");
        houseOwner.signContract();
        System.out.println("中介:合同已签,收取中介费2%");
    }
}

// 4. 客户端使用
public class StaticProxyDemo {
    public static void main(String[] args) {
        HouseService agent = new HouseAgent();
        agent.findHouse();
        agent.negotiatePrice();
        agent.signContract();
    }
}

示例二:图片加载代理(虚拟代理)

// 1. 图片接口
interface Image {
    void display();
}

// 2. 真实图片类(重量级对象)
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(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("图片加载完成: " + fileName);
    }

    @Override
    public void display() {
        System.out.println("显示图片: " + fileName);
    }
}

// 3. 图片代理类
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();
    }
}

// 4. 客户端使用
public class VirtualProxyDemo {
    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("\n第一次显示图片2:");
        image2.display();

        System.out.println("\n第二次显示图片1(已缓存):");
        image1.display();
    }
}

示例三:权限控制代理(动态代理)

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

// 1. 用户服务接口
interface UserService {
    void viewProfile();
    void editProfile();
    void deleteAccount();
}

// 2. 用户服务实现
class UserServiceImpl implements UserService {
    @Override
    public void viewProfile() {
        System.out.println("查看用户资料");
    }

    @Override
    public void editProfile() {
        System.out.println("编辑用户资料");
    }

    @Override
    public void deleteAccount() {
        System.out.println("删除用户账户");
    }
}

// 3. 权限检查处理器
class PermissionHandler implements InvocationHandler {
    private Object target;
    private String userRole;

    public PermissionHandler(Object target, String userRole) {
        this.target = target;
        this.userRole = userRole;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String methodName = method.getName();

        // 权限检查
        if (methodName.equals("deleteAccount") && !"admin".equals(userRole)) {
            System.out.println("权限不足:只有管理员可以删除账户");
            return null;
        }

        if (methodName.equals("editProfile") && "guest".equals(userRole)) {
            System.out.println("权限不足:游客不能编辑资料");
            return null;
        }

        // 记录日志
        System.out.println("用户角色: " + userRole + ", 执行方法: " + methodName);

        // 调用真实方法
        return method.invoke(target, args);
    }
}

// 4. 客户端使用
public class DynamicProxyDemo {
    public static void main(String[] args) {
        UserService userService = new UserServiceImpl();

        // 创建普通用户代理
        UserService normalUserProxy = (UserService) Proxy.newProxyInstance(
            UserService.class.getClassLoader(),
            new Class<?>[] { UserService.class },
            new PermissionHandler(userService, "user")
        );

        // 创建游客代理
        UserService guestProxy = (UserService) Proxy.newProxyInstance(
            UserService.class.getClassLoader(),
            new Class<?>[] { UserService.class },
            new PermissionHandler(userService, "guest")
        );

        // 创建管理员代理
        UserService adminProxy = (UserService) Proxy.newProxyInstance(
            UserService.class.getClassLoader(),
            new Class<?>[] { UserService.class },
            new PermissionHandler(userService, "admin")
        );

        System.out.println("=== 普通用户操作 ===");
        normalUserProxy.viewProfile();
        normalUserProxy.editProfile();
        normalUserProxy.deleteAccount();

        System.out.println("\n=== 游客操作 ===");
        guestProxy.viewProfile();
        guestProxy.editProfile();
        guestProxy.deleteAccount();

        System.out.println("\n=== 管理员操作 ===");
        adminProxy.viewProfile();
        adminProxy.editProfile();
        adminProxy.deleteAccount();
    }
}

代理模式的优点

  1. 控制访问:可以在访问真实对象前后添加额外的控制逻辑
  2. 延迟加载:虚拟代理可以延迟创建重量级对象
  3. 权限控制:可以控制对真实对象的访问权限
  4. 日志记录:可以记录对真实对象的访问日志
  5. 缓存:可以缓存真实对象的结果

代理模式的缺点

  1. 增加复杂性:引入了额外的代理层,增加了系统的复杂性
  2. 性能开销:代理对象会带来一定的性能开销
  3. 代码冗余:静态代理需要为每个代理类编写大量重复代码

使用场景

  1. 远程代理:控制对远程对象的访问
  2. 虚拟代理:延迟加载重量级对象
  3. 保护代理:控制对敏感对象的访问权限
  4. 缓存代理:为开销大的操作提供缓存
  5. 日志代理:记录对对象的访问日志

总结

代理模式就像生活中的各种"中介"一样,它们代表真实对象处理各种事务,并在处理过程中添加自己的逻辑。这种模式让我们可以在不修改原有代码的情况下,为对象添加新的功能和行为。

最近更新:: 2025/12/29 11:07
Contributors: Duke
Prev
装饰器模式
Next
外观模式