结构型-代理模式

1. 项目结构

bash 复制代码
	proxy-pattern-demo/
	├── pom.xml
	├── src/
	│   └── main/
	│       └── java/
	│           └── com/
	│               └── demo/
	│                   ├── proxy/
	│                   │   ├── Image.java
	│                   │   ├── RealImage.java
	│                   │   ├── ImageProxy.java
	│                   │   └── ProtectionProxy/
	│                   │       ├── Document.java
	│                   │       ├── RealDocument.java
	│                   │       ├── DocumentProxy.java
	│                   │       └── UserRole.java
	│                   ├── dynamic/
	│                   │   ├── UserService.java
	│                   │   ├── UserServiceImpl.java
	│                   │   ├── LoggingInvocationHandler.java
	│                   │   └── CacheInvocationHandler.java
	│                   └── App.java

Maven 配置文件 (pom.xml)

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.demo</groupId>
    <artifactId>proxy-pattern-demo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <properties>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.24</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

2. 代码实现

  1. 静态代理示例:
    Image.java (接口)

    java 复制代码
    package com.demo.proxy;
    
    public interface Image {
        void display();
        String getFileName();
    }

    RealImage.java (真实对象)

    java 复制代码
    package com.demo.proxy;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    
    @Data
    @AllArgsConstructor
    public 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) {
                Thread.currentThread().interrupt();
            }
        }
        
        @Override
        public void display() {
            System.out.println("显示图片: " + fileName);
        }
    }

    ImageProxy.java (代理类)

    java 复制代码
    package com.demo.proxy;
    
    import lombok.Data;
    
    @Data
    public class ImageProxy implements Image {
        private RealImage realImage;
        private String fileName;
        
        public ImageProxy(String fileName) {
            this.fileName = fileName;
        }
        
        @Override
        public void display() {
            if (realImage == null) {
                realImage = new RealImage(fileName);
            }
            realImage.display();
        }
        
        @Override
        public String getFileName() {
            return fileName;
        }
        
        // 代理的额外功能
        public void showImageInfo() {
            System.out.println("图片代理信息: " + fileName);
            System.out.println("真实对象是否已加载: " + (realImage != null));
        }
    }
  2. 保护代理示例
    UserRole.java (用户角色枚举)

    java 复制代码
    package com.demo.proxy.ProtectionProxy;
    
    public enum UserRole {
        GUEST,
        USER,
        ADMIN
    }

    Document.java (接口)

    java 复制代码
    package com.demo.proxy.ProtectionProxy;
    
    public interface Document {
        void view();
        void edit();
        void delete();
        String getContent();
    }

    RealDocument.java (真实文档)

    java 复制代码
    package com.demo.proxy.ProtectionProxy;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    
    @Data
    @AllArgsConstructor
    public class RealDocument implements Document {
        private String content;
        private String author;
        
        @Override
        public void view() {
            System.out.println("查看文档内容: " + content);
        }
        
        @Override
        public void edit() {
            System.out.println("编辑文档: " + content);
        }
        
        @Override
        public void delete() {
            System.out.println("删除文档: " + content);
        }
        
        @Override
        public String getContent() {
            return content;
        }
    }

    DocumentProxy.java (保护代理)

    java 复制代码
    package com.demo.proxy.ProtectionProxy;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    
    @Data
    @AllArgsConstructor
    public class DocumentProxy implements Document {
        private RealDocument realDocument;
        private UserRole userRole;
        
        public DocumentProxy(String content, String author, UserRole userRole) {
            this.realDocument = new RealDocument(content, author);
            this.userRole = userRole;
        }
        
        @Override
        public void view() {
            // 所有角色都可以查看
            System.out.println("[" + userRole + "] 请求查看文档");
            realDocument.view();
        }
        
        @Override
        public void edit() {
            // 只有USER和ADMIN可以编辑
            if (userRole == UserRole.USER || userRole == UserRole.ADMIN) {
                System.out.println("[" + userRole + "] 请求编辑文档");
                realDocument.edit();
            } else {
                System.out.println("[" + userRole + "] 没有编辑权限");
            }
        }
        
        @Override
        public void delete() {
            // 只有ADMIN可以删除
            if (userRole == UserRole.ADMIN) {
                System.out.println("[" + userRole + "] 请求删除文档");
                realDocument.delete();
            } else {
                System.out.println("[" + userRole + "] 没有删除权限");
            }
        }
        
        @Override
        public String getContent() {
            return realDocument.getContent();
        }
    }
  3. 动态代理示例
    UserService.java (接口)

    java 复制代码
    package com.demo.dynamic;
    
    public interface UserService {
        String getUserInfo(int userId);
        void updateUserInfo(int userId, String info);
        int getUserCount();
    }

    UserServiceImpl.java (实现类)

    java 复制代码
    package com.demo.dynamic;
    
    import lombok.extern.slf4j.Slf4j;
    
    @Slf4j
    public class UserServiceImpl implements UserService {
        @Override
        public String getUserInfo(int userId) {
            log.info("获取用户信息: {}", userId);
            // 模拟数据库查询
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            return "用户" + userId + "的信息";
        }
        
        @Override
        public void updateUserInfo(int userId, String info) {
            log.info("更新用户信息: {} -> {}", userId, info);
            // 模拟数据库更新
            try {
                Thread.sleep(800);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
        
        @Override
        public int getUserCount() {
            log.info("获取用户总数");
            return 100;
        }
    }

    LoggingInvocationHandler.java (日志增强处理器)

    java 复制代码
    package com.demo.dynamic;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.util.Arrays;
    import java.util.Date;
    
    public class LoggingInvocationHandler implements InvocationHandler {
        private final Object target;
        
        public LoggingInvocationHandler(Object target) {
            this.target = target;
        }
        
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            long startTime = System.currentTimeMillis();
            System.out.println("[" + new Date() + "] 开始调用方法: " + method.getName());
            System.out.println("方法参数: " + (args != null ? Arrays.toString(args) : "无"));
            
            try {
                Object result = method.invoke(target, args);
                long endTime = System.currentTimeMillis();
                System.out.println("[" + new Date() + "] 方法调用完成: " + method.getName());
                System.out.println("执行时间: " + (endTime - startTime) + "ms");
                System.out.println("返回结果: " + result);
                return result;
            } catch (Exception e) {
                System.out.println("方法调用异常: " + e.getMessage());
                throw e;
            }
        }
    }

    CacheInvocationHandler.java (缓存增强处理器)

    java 复制代码
    package com.demo.dynamic;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.util.HashMap;
    import java.util.Map;
    
    public class CacheInvocationHandler implements InvocationHandler {
        private final Object target;
        private final Map<String, Object> cache = new HashMap<>();
        
        public CacheInvocationHandler(Object target) {
            this.target = target;
        }
        
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            // 只缓存getUserInfo方法
            if ("getUserInfo".equals(method.getName()) && args != null && args.length == 1) {
                String cacheKey = method.getName() + "_" + args[0];
                
                if (cache.containsKey(cacheKey)) {
                    System.out.println("从缓存获取数据: " + cacheKey);
                    return cache.get(cacheKey);
                }
                
                Object result = method.invoke(target, args);
                cache.put(cacheKey, result);
                System.out.println("将数据存入缓存: " + cacheKey);
                return result;
            }
            
            return method.invoke(target, args);
        }
    }

主程序 App.java

java 复制代码
package com.demo;

import com.demo.proxy.Image;
import com.demo.proxy.ImageProxy;
import com.demo.proxy.ProtectionProxy.Document;
import com.demo.proxy.ProtectionProxy.DocumentProxy;
import com.demo.proxy.ProtectionProxy.UserRole;
import com.demo.dynamic.UserService;
import com.demo.dynamic.UserServiceImpl;
import com.demo.dynamic.LoggingInvocationHandler;
import com.demo.dynamic.CacheInvocationHandler;

import java.lang.reflect.Proxy;

public class App {
    public static void main(String[] args) {
        System.out.println("========== 代理模式演示 ==========\n");
        
        // 1. 静态代理演示 - 虚拟代理
        System.out.println("1. 静态代理演示 - 虚拟代理");
        System.out.println("---------------------------");
        Image image = new ImageProxy("test.jpg");
        
        // 第一次调用会加载真实对象
        System.out.println("第一次调用display():");
        image.display();
        System.out.println();
        
        // 第二次调用直接使用已加载的对象
        System.out.println("第二次调用display():");
        image.display();
        System.out.println();
        
        // 2. 保护代理演示
        System.out.println("2. 保护代理演示");
        System.out.println("---------------------------");
        
        // 不同角色的访问权限
        UserRole[] roles = {UserRole.GUEST, UserRole.USER, UserRole.ADMIN};
        
        for (UserRole role : roles) {
            System.out.println("\n--- " + role + " 角色操作 ---");
            Document doc = new DocumentProxy("机密文档内容", "admin", role);
            
            doc.view();
            doc.edit();
            doc.delete();
        }
        
        System.out.println();
        
        // 3. 动态代理演示
        System.out.println("3. 动态代理演示");
        System.out.println("---------------------------");
        
        UserService userService = new UserServiceImpl();
        
        // 创建日志代理
        UserService loggingProxy = (UserService) Proxy.newProxyInstance(
            UserService.class.getClassLoader(),
            new Class[]{UserService.class},
            new LoggingInvocationHandler(userService)
        );
        
        System.out.println("\n--- 日志代理测试 ---");
        loggingProxy.getUserInfo(1);
        loggingProxy.updateUserInfo(1, "新信息");
        
        // 创建缓存代理
        UserService cacheProxy = (UserService) Proxy.newProxyInstance(
            UserService.class.getClassLoader(),
            new Class[]{UserService.class},
            new CacheInvocationHandler(userService)
        );
        
        System.out.println("\n--- 缓存代理测试 ---");
        System.out.println("第一次调用getUserInfo(1):");
        cacheProxy.getUserInfo(1);
        
        System.out.println("\n第二次调用getUserInfo(1):");
        cacheProxy.getUserInfo(1);
        
        System.out.println("\n调用getUserInfo(2):");
        cacheProxy.getUserInfo(2);
        
        // 4. 组合代理 (代理链)
        System.out.println("\n--- 代理链测试 (日志 + 缓存) ---");
        UserService chainProxy = (UserService) Proxy.newProxyInstance(
            UserService.class.getClassLoader(),
            new Class[]{UserService.class},
            new CacheInvocationHandler(
                (UserService) Proxy.newProxyInstance(
                    UserService.class.getClassLoader(),
                    new Class[]{UserService.class},
                    new LoggingInvocationHandler(userService)
                )
            )
        );
        
        System.out.println("\n第一次调用getUserInfo(3):");
        chainProxy.getUserInfo(3);
        
        System.out.println("\n第二次调用getUserInfo(3):");
        chainProxy.getUserInfo(3);
        
        System.out.println("\n========== 演示结束 ==========");
    }
}

3. 构建和运行

  1. 编译项目

    bash 复制代码
    mvn clean compile
  2. 运行项目

    bash 复制代码
    mvn exec:java -Dexec.mainClass="com.demo.App"

4. 核心概念

  • 静态代理

    • ImageProxy: 虚拟代理,延迟加载真实图片对象

    • DocumentProxy: 保护代理,根据用户角色控制访问权限

  • 动态代理

    • LoggingInvocationHandler: 为方法调用添加日志记录

    • CacheInvocationHandler: 为方法添加缓存功能

    • 可以灵活组合多个代理处理器

  • 代理模式优点

    • 职责清晰,真实角色只需关注业务逻辑

    • 高扩展性,可以方便地添加新功能

    • 智能化,动态代理可以灵活处理各种场景

相关推荐
syt_10133 天前
设计模式之-享元模式
javascript·设计模式·享元模式
__万波__15 天前
二十三种设计模式(十一)--享元模式
java·设计模式·享元模式
ZouZou老师17 天前
C++设计模式之享元模式:以家具生产为例
c++·设计模式·享元模式
雨中飘荡的记忆23 天前
设计模式之享元模式详解
java·设计模式·享元模式
Jomurphys23 天前
设计模式 - 享元模式 Flyweight Pattern
android·设计模式·享元模式
明洞日记1 个月前
【设计模式手册011】享元模式 - 共享细粒度对象的高效之道
java·设计模式·享元模式
Yeniden2 个月前
【设计模式】享元模式(Flyweight)大白话讲解!
java·设计模式·享元模式
杯莫停丶2 个月前
设计模式之:享元模式
java·设计模式·享元模式