课程大纲 / Lesson 11
Proxy 结构型

Proxy · 代理

为真实对象提供一个替身(Proxy),以控制对它的访问。

01

理解代理模式:通过 Proxy 控制对真实对象的访问,实现延迟加载、访问控制等功能

02

掌握远程代理、虚代理(缓存)、保护代理、智能引用等多种代理变体

03

理解代理与装饰器模式的区别:代理控制访问,装饰器动态增加功能

04

了解代理在图片懒加载、视频缓存、权限控制、远程服务调用中的应用

核心概念
替身控制访问延迟加载缓存远程代理智能引用
classDiagram class thirdpartyyoutubelib { <<interface>> +listvideos() list~video~ +getvideoinfo(id string) video +downloadvideo(id string) byte[] } class thirdpartyyoutubeclass { <<stateless>> +listvideos() list~video~ +getvideoinfo(id string) video +downloadvideo(id string) byte[] } class youtubecacheproxy { -youtubeservice thirdpartyyoutubelib -listcache list~video~ -videocache hashmap~string,video~ -listcachedtime long +listvideos() list~video~ +getvideoinfo(id string) video +downloadvideo(id string) byte[] } class video { +id string +title string +data string +video(id string,title string) } class youtubedownloader { -factory thirdpartyyoutubelib +renderlistpage() +rendervideopage(id string) } thirdpartyyoutubelib <|.. thirdpartyyoutubeclass thirdpartyyoutubelib <|.. youtubecacheproxy youtubecacheproxy *-- thirdpartyyoutubelib youtubedownloader o-- thirdpartyyoutubelib thirdpartyyoutubelib ..> video

代理与真实服务实现同一接口,可在转发请求前后增加缓存、鉴权等控制

点击 Run 通过代理下载...
import java.util.List;

/** 第三方视频库接口(模拟真实服务)*/
public interface ThirdPartyYouTubeLib {
    List<Video> listVideos();
    Video getVideoInfo(String id);
    byte[] downloadVideo(String id);
}
import java.util.HashMap;
import java.util.List;

/** 缓存代理:实现同一接口,在调用真实服务前检查缓存 */
public class YouTubeCacheProxy implements ThirdPartyYouTubeLib {
    private ThirdPartyYouTubeLib youtubeService;
    private List<Video> listCache;
    private HashMap<String, Video> videoCache = new HashMap<>();
    private long listCachedTime = 0;

    public YouTubeCacheProxy() {
        youtubeService = new ThirdPartyYouTubeClass();
    }

    public List<Video> listVideos() {
        if (listCache == null || System.currentTimeMillis() - listCachedTime > 3600000) {
            listCache = youtubeService.listVideos();
            listCachedTime = System.currentTimeMillis();
        }
        return listCache;
    }

    public Video getVideoInfo(String id) {
        if (!videoCache.containsKey(id)) {
            videoCache.put(id, youtubeService.getVideoInfo(id));
        }
        return videoCache.get(id);
    }

    public byte[] downloadVideo(String id) {
        return youtubeService.downloadVideo(id);
    }
}
/** 视频数据对象 */
public class Video {
    public String id;
    public String title;
    public String data;

    public Video(String id, String title) {
        this.id = id; this.title = title;
    }
}
/** 视频下载器:客户端使用,不感知是否使用了代理 */
public class YouTubeDownloader {
    private ThirdPartyYouTubeLib factory;

    public YouTubeDownloader(ThirdPartyYouTubeLib factory) {
        this.factory = factory;
    }

    public void renderListPage() {
        System.out.println("Fetching video list...");
    }

    public void renderVideoPage(String videoId) {
        System.out.println("Fetching info for " + videoId + "...");
    }
}
public class Demo {
    public static void main(String[] args) {
        ThirdPartyYouTubeLib youtubeService =
            new YouTubeCacheProxy();
        YouTubeDownloader downloader =
            new YouTubeDownloader(youtubeService);

        downloader.renderListPage();
        downloader.renderVideoPage("vid1");
        downloader.renderListPage(); // 第二次调用走缓存
    }
}
import java.util.List;

/** 模拟真实第三方服务 */
public class ThirdPartyYouTubeClass implements ThirdPartyYouTubeLib {
    public List<Video> listVideos() {
        return List.of(new Video("vid1", "Design Patterns"));
    }
    public Video getVideoInfo(String id) {
        return new Video(id, "Design Patterns");
    }
    public byte[] downloadVideo(String id) {
        return new byte[0];
    }
}
◈

代理控制对真实对象的访问

YouTubeCacheProxy 实现与 ThirdPartyYouTubeLib 相同接口,客户端以为在用真实服务,实际上代理在中间层做了缓存逻辑。

◈

虚代理(缓存)延迟加载

首次调用 listVideos() 真实请求,后续调用直接返回缓存,避免重复网络请求和带宽消耗。

◈

代理 vs. 装饰器 vs. 适配器

代理:控制访问(替身);装饰器:动态增加功能;适配器:转换接口。三者都是包装已有对象,目的不同。

◈

典型应用场景

图片懒加载(先显示占位图)、视频缓存(减少带宽)、权限控制(保护代理)、远程服务调用(远程代理如 Java RMI)、日志记录(智能引用)。