MST

星途 面试题库

面试题:Java装饰器模式与代理模式的区别及应用选择

阐述Java装饰器模式和代理模式的主要区别,包括它们的意图、结构和适用场景。假设你正在开发一个图片处理系统,某些图片需要在显示前进行加密处理,你会选择使用装饰器模式还是代理模式?请详细说明原因并给出大致的代码实现思路。
16.2万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

区别

  1. 意图
    • 装饰器模式:动态地给一个对象添加一些额外的职责,就增加功能来说,装饰器模式相比生成子类更为灵活。重点在于增强对象的功能。
    • 代理模式:为其他对象提供一种代理以控制对这个对象的访问。主要目的是控制对目标对象的访问,比如权限控制、延迟加载等。
  2. 结构
    • 装饰器模式:装饰器和被装饰对象实现相同的接口,装饰器持有被装饰对象的引用,并在自身的方法中调用被装饰对象的方法,同时可以添加额外的行为。
    • 代理模式:代理对象和目标对象实现相同的接口,代理对象内部持有目标对象的引用,代理对象控制对目标对象的访问,可能在访问目标对象前后添加一些处理逻辑。
  3. 适用场景
    • 装饰器模式:适用于在不改变原有类结构的情况下,动态地为对象添加新功能,比如添加日志记录、缓存等功能。
    • 代理模式:适用于需要控制对对象的访问,如远程代理(访问远程对象)、虚拟代理(延迟加载)、保护代理(权限控制)等场景。

图片处理系统选择及原因

在图片处理系统中,对于某些图片需要在显示前进行加密处理,更适合使用装饰器模式。原因是我们主要目的是为图片显示功能添加加密这个额外职责,而不是控制对图片显示的访问。使用装饰器模式可以在不改变原有图片显示类结构的基础上,动态地为图片显示添加加密功能,符合开闭原则。

大致代码实现思路

  1. 定义图片显示接口
public interface Image {
    void display();
}
  1. 实现具体图片类
public class ConcreteImage implements Image {
    private String imagePath;
    public ConcreteImage(String imagePath) {
        this.imagePath = imagePath;
    }
    @Override
    public void display() {
        System.out.println("Displaying image from: " + imagePath);
    }
}
  1. 定义装饰器抽象类
public abstract class ImageDecorator implements Image {
    protected Image decoratedImage;
    public ImageDecorator(Image decoratedImage) {
        this.decoratedImage = decoratedImage;
    }
    @Override
    public void display() {
        decoratedImage.display();
    }
}
  1. 实现加密装饰器类
public class EncryptionImageDecorator extends ImageDecorator {
    public EncryptionImageDecorator(Image decoratedImage) {
        super(decoratedImage);
    }
    private void encryptImage() {
        System.out.println("Encrypting image before display...");
    }
    @Override
    public void display() {
        encryptImage();
        super.display();
    }
}
  1. 使用示例
public class Main {
    public static void main(String[] args) {
        Image image = new ConcreteImage("path/to/image.jpg");
        Image encryptedImage = new EncryptionImageDecorator(image);
        encryptedImage.display();
    }
}