CHARLIE SAYS

查理如是说
DATE 2026-08-24
THEME
SERIES / DESIGN_PATTERNS / P-109 · 设计模式

设计模式 015:代理(Proxy)

代理模式(Proxy pattern)为另一个对象提供一个替身或占位符,以控制对这个对象的访问。客户代码直接打交道的是代理而非真实对象,由代理决定何时、以什么方式把请求转交给真实对象。本文是结构型模式的最后一篇。

意图

控制对其它对象的访问。

四类代理

按控制访问的方式,代理可以分为四类:

  • 远程代理(Remote Proxy):控制对远程对象(不同地址空间)的访问,它负责将请求及其参数进行编码,并向不同地址空间中的对象发送已经编码的请求。
  • 虚拟代理(Virtual Proxy):根据需要创建开销很大的对象,它可以缓存实体的附加信息,以便延迟对它的访问。例如在网站加载一个很大图片时,不能马上完成,可以用虚拟代理缓存图片的大小信息,然后生成一张临时图片代替原始图片。
  • 保护代理(Protection Proxy):按权限控制对象的访问,它负责检查调用者是否具有实现一个请求所必须的访问权限。
  • 智能代理(Smart Reference):取代了简单的指针,它在访问对象时执行一些附加操作:记录对象的引用次数;当第一次引用一个持久化对象时,将它装入内存;在访问一个实际对象前,检查是否已经锁定了它,以确保其它对象不能改变它。

类图

Image 是统一接口,HighResolutionImage 是真实对象,ImageProxy 是它的代理:两者实现同一接口,代理持有真实对象的引用,从而可以在访问前后施加控制。原文图片丢失,据文字重绘。

classDiagram
    class Image {
        <<interface>>
        +showImage()
    }
    class HighResolutionImage {
        -URL imageURL
        -long startTime
        -int height
        -int width
        +getHeight() int
        +getWidth() int
        +isLoad() boolean
        +showImage()
    }
    class ImageProxy {
        -HighResolutionImage highResolutionImage
        +showImage()
    }
    Image <|.. HighResolutionImage
    Image <|.. ImageProxy
    ImageProxy o-- HighResolutionImage : 代理

实现

以下是一个虚拟代理的实现,模拟了图片延迟加载的情况下使用与图片大小相等的临时内容去替换原始图片,直到图片加载完成才将图片显示出来。

先定义统一接口:

public interface Image {
    void showImage();
}

真实对象,用 isLoad() 模拟加载耗时:

public class HighResolutionImage implements Image {

    private URL imageURL;
    private long startTime;
    private int height;
    private int width;

    public int getHeight() {
        return height;
    }

    public int getWidth() {
        return width;
    }

    public HighResolutionImage(URL imageURL) {
        this.imageURL = imageURL;
        this.startTime = System.currentTimeMillis();
        this.width = 600;
        this.height = 600;
    }

    public boolean isLoad() {
        // 模拟图片加载,延迟 3s 加载完成
        long endTime = System.currentTimeMillis();
        return endTime - startTime > 3000;
    }

    @Override
    public void showImage() {
        System.out.println("Real Image: " + imageURL);
    }
}

虚拟代理在图片加载完成前,一直显示与图片大小相同的临时内容:

public class ImageProxy implements Image {

    private HighResolutionImage highResolutionImage;

    public ImageProxy(HighResolutionImage highResolutionImage) {
        this.highResolutionImage = highResolutionImage;
    }

    @Override
    public void showImage() {
        while (!highResolutionImage.isLoad()) {
            try {
                System.out.println("Temp Image: " + highResolutionImage.getWidth()
                        + " " + highResolutionImage.getHeight());
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        highResolutionImage.showImage();
    }
}
public class ImageViewer {

    public static void main(String[] args) throws Exception {
        String image = "http://image.jpg";
        URL url = new URL(image);
        HighResolutionImage highResolutionImage = new HighResolutionImage(url);
        ImageProxy imageProxy = new ImageProxy(highResolutionImage);
        imageProxy.showImage();
    }
}

JDK 中的应用

  • java.lang.reflect.Proxy
  • RMI

系列导航

参考资料

  • 弗里曼. Head First 设计模式 [M]. 中国电力出版社, 2007.
  • Gamma E. 设计模式: 可复用面向对象软件的基础 [M]. 机械工业出版社, 2007.
  • Bloch J. Effective java [M]. Addison-Wesley Professional, 2017.
  • Design Patterns
  • Design patterns implemented in Java
  • The breakdown of design patterns in JDK
← Angular 22+ 教程 15:动态组件 Dynamic Components 目录 软件工程 015:开发实践:领域驱动开发(DDD) →
← 返回文章列表