意图区别
- 装饰器模式:主要意图是在不改变原有对象结构的情况下,动态地给对象添加新的功能。它强调的是对功能的增强,就像给一个对象“穿衣服”,一件一件地添加功能。
- 代理模式:意图是为其他对象提供一种代理以控制对这个对象的访问。它主要用于控制对目标对象的访问,比如权限控制、延迟加载等,就像是一个“中介”,通过它来访问目标对象。
使用场景区别
- 装饰器模式:当需要在运行时给对象添加新功能,且不希望通过继承来实现(避免子类过多)时使用。例如,在Java的I/O流中,
BufferedInputStream
就是通过装饰器模式给InputStream
添加了缓冲功能。
- 代理模式:适用于需要对目标对象的访问进行控制,如远程代理(访问远程对象)、虚拟代理(延迟加载大对象)、保护代理(控制访问权限)等场景。比如,在访问数据库连接池时,使用代理来控制对连接的获取和释放。
实现方式区别
- 装饰器模式:装饰器和被装饰对象实现同一个接口,装饰器内部持有被装饰对象的引用。在装饰器的方法中,调用被装饰对象的方法,并在前后添加额外功能。
- 代理模式:代理类和目标类实现同一个接口,代理类内部持有目标类的引用。代理类在方法中控制对目标类方法的调用,如进行权限检查、记录日志等操作。
代码示例
装饰器模式示例
// 抽象组件
interface Shape {
void draw();
}
// 具体组件
class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Drawing Rectangle");
}
}
// 抽象装饰器
abstract class ShapeDecorator implements Shape {
protected Shape decoratedShape;
public ShapeDecorator(Shape decoratedShape) {
this.decoratedShape = decoratedShape;
}
@Override
public void draw() {
decoratedShape.draw();
}
}
// 具体装饰器
class RedShapeDecorator extends ShapeDecorator {
public RedShapeDecorator(Shape decoratedShape) {
super(decoratedShape);
}
@Override
public void draw() {
decoratedShape.draw();
setRedBorder(decoratedShape);
}
private void setRedBorder(Shape decoratedShape) {
System.out.println("Border Color: Red");
}
}
// 测试
public class DecoratorPatternDemo {
public static void main(String[] args) {
Shape rectangle = new Rectangle();
Shape redRectangle = new RedShapeDecorator(new Rectangle());
rectangle.draw();
redRectangle.draw();
}
}
代理模式示例
// 抽象接口
interface Image {
void display();
}
// 真实主题
class RealImage implements Image {
private String fileName;
public RealImage(String fileName) {
this.fileName = fileName;
loadFromDisk(fileName);
}
@Override
public void display() {
System.out.println("Displaying " + fileName);
}
private void loadFromDisk(String fileName) {
System.out.println("Loading " + fileName);
}
}
// 代理主题
class ProxyImage implements Image {
private String fileName;
private RealImage realImage;
public ProxyImage(String fileName) {
this.fileName = fileName;
}
@Override
public void display() {
if (realImage == null) {
realImage = new RealImage(fileName);
}
realImage.display();
}
}
// 测试
public class ProxyPatternDemo {
public static void main(String[] args) {
Image image = new ProxyImage("test_10mb.jpg");
// 图像将从磁盘加载
image.display();
System.out.println("");
// 图像不需要从磁盘加载
image.display();
}
}