装饰器模式(Decorator Pattern)和代理模式(Proxy Pattern)都是结构型设计模式,它们在结构上看起来相似,因为两者都是通过包装一个类来扩展其功能。但它们的意图、用途和实现方式存在明显差异。
装饰器模式:
目的:
- 主要用于添加新的功能到对象,而不改变其接口。
- 通过添加“装饰”的方式动态地给对象附加额外的职责。
- 可以灵活地组合多个装饰器来增强对象的行为。
适用场景:
- 当需要透明且动态地扩展类的功能时。
- 当希望一个对象有多种变化,或者对象的变化可以组合时。
- 在不想增加很多子类的情况下扩展类。
Java示例:
假设我们有一个简单的TextView类,我们想动态地为其添加边框和滚动条而不修改原始类。
// 基本组件接口
interface VisualComponent {
void draw();
}
// 具体组件类
class TextView implements VisualComponent {
@Override
public void draw() {
System.out.println("Drawing TextView");
}
}
// 抽象装饰器
abstract class Decorator implements VisualComponent {
protected VisualComponent component;
public Decorator(VisualComponent component) {
this.component = component;
}
public void draw() {
component.draw();
Delegation
}
}
// 具体装饰器:边框
class BorderDecorator extends Decorator {
public BorderDecorator(VisualComponent component) {
super(component);
}
@Override
public void draw() {
super.draw();
drawBorder();
}
private void drawBorder() {
System.out.println("Drawing border");
}
}
// 具体装饰器:滚动条
class ScrollDecorator extends Decorator {
public ScrollDecorator(VisualComponent component) {
super(component);
}
@Override
public void draw() {
super.draw();
drawScrollbar();
}
private void drawScrollbar() {
System.out.println("Drawing scrollbar");
}
}
public class DecoratorDemo {
public static void main(String[] args) {
VisualComponent textView = new TextView();
VisualComponent borderedTextView = new BorderDecorator(textView);
VisualComponent scrollableBorderedTextView = new ScrollDecorator(borderedTextView);
scrollableBorderedTextView.draw();
}
}
在这个例子中,原始的TextView不会被修改,我们通过装饰器BorderDecorator和ScrollDecorator分别添加了边框和滚动条的功能。
代理模式:
目的:
- 控制对其他对象的访问,相当于该对象的一个代表,客户端通常通过代理间接访问那个对象。
- 客户端可能需要访问控制、延迟初始化、远程对象访问等。
适用场景:
- 当需要对原有对象的操作进行控制或增强时。
- 当需要延迟对象的创建时(虚拟代理)。
- 当需要为远程对象提供本地代表时(远程代理)。
- 当需要记录对象的访问日志时(保护代理)。
Java示例:
设想有一个昂贵的数据库连接类,我们不希望除非必要否则不创建连接。我们可以使用代理模式来实现懒加载。
// 接口
interface Database {
void connect();
}
// 实际数据库连接类
class RealDatabase implements Database {
@Override
public void connect() {
System.out.println("Connecting to a real database.");
}
}
// 数据库代理类
class DatabaseProxy implements Database {
private RealDatabase realDatabase;
@Override
public void connect() {
if (realDatabase == null) {
realDatabase = new RealDatabase();
}
realDatabase.connect();
}
}
public class ProxyDemo {
public static void main(String[] args) {
Database db = new DatabaseProxy();
db.connect();
// 连接将被延迟到实际被需要的时候
}
}
在这个例子中,DatabaseProxy作为RealDatabase的代理,它延迟了真实数据库连接对象的创建直到实际需要连接时。客户端代码使用DatabaseProxy而无需关心真正的数据库连接何时建立。
区别总结:
装饰器模式关注于在不改变接口的前提下增加对象的功能,是一种结构性扩展;而代理模式关注于控制对对象的访问,是一种控制性模式。装饰器允许递归组合,而代理通常不涉及递归。代理模式中的代理知道它正在代理的对象,而装饰器只关心接口,不需要知道具体的类。
本篇文章来源于微信公众号: 互联网面试小帮手
微信扫描下方的二维码阅读本文

Comments NOTHING