装饰模式和代理模式的区别


原文 : http://www.cnblogs.com/jaredlam/archive/2011/11/08/2241089.html

学习AOP时,教材上面都说使用的是动态代理,可是在印象中代理模式一直都是控制访问什么的,怎么又动态增加行为了,动态增加行为不是装饰器模式吗?于是 找了很多资料,想弄清楚这两者之间到底有什么区别。结果发现这一篇英文文章讲的很清晰,就翻译一下,供参考。       

        首先,让我们先看一下下面的这两个UML类图,他们分别描述了装饰器模式和代理模式的基本实现。

                   

                    

        这两个图可能使我们产生困惑。这两个设计模式看起来很像。对装饰器模式来说,装饰者(decorator)和被装饰者(decoratee)都实现同一个 接口。对代理模式来说,代理类(proxy class)和真实处理的类(real class)都实现同一个接口。此外,不论我们使用哪一个模式,都可以很容易地在真实对象的方法前面或者后面加上自定义的方法。

        然而,实际上,在装饰器模式和代理模式之间还是有很多差别的。装饰器模式关注于在一个对象上动态的添加方法,然而代理模式关注于控制对对象的访问。换句话 说,用代理模式,代理类(proxy class)可以对它的客户隐藏一个对象的具体信息。因此,当使用代理模式的时候,我们常常在一个代理类中创建一个对象的实例。并且,当我们使用装饰器模 式的时候,我们通常的做法是将原始对象作为一个参数传给装饰者的构造器。

        我们可以用另外一句话来总结这些差别:使用代理模式,代理和真实对象之间的的关系通常在编译时就已经确定了,而装饰者能够在运行时递归地被构造。    

代理模式:

复制代码
//代理模式
public class Proxy implements Subject{

       private Subject subject;
       public Proxy(){
             //关系在编译时确定
            subject = new RealSubject();
       }
       public void doAction(){
             ….
             subject.doAction();
             ….
       }
}
复制代码
复制代码
//代理的客户
public class Client{
        public static void main(String[] args){
             //客户不知道代理委托了另一个对象
             Subject subject = new Proxy();
             …
        }
}
复制代码

装饰模式:

复制代码
//装饰器模式
public class Decorator implements Component{
        private Component component;
        public Decorator(Component component){
            this.component = component
        }
       public void operation(){
            ….
            component.operation();
            ….
       }
}
复制代码
复制代码
//装饰器的客户
public class Client{
        public static void main(String[] args){
            //客户指定了装饰者需要装饰的是哪一个类
            Component component = new Decorator(new ConcreteComponent());
            …
        }
}
二者还有一个区别就是 代理可以控制对象的访问权,而装饰只能添加新的功能不能改变原有对象 !


<think>好的,我现在需要回答用户关于Java中装饰模式代理模式区别及用法对比的问题。用户已经提供了一些相关的引用资料,我需要结合这些资料以及之前的知识来组织回答。 首先,我需要回顾装饰模式代理模式的基本概念。装饰模式用于动态地给对象添加职责,而代理模式则是控制对对象的访问。根据引用[1],这两个模式都基于组合,结构上相似,容易混淆。引用[3][4]提到,装饰模式强调功能扩展,代理模式强调访问控制。此外,代理模式可能在内部创建目标对象,而装饰模式通过构造函数传入目标对象。 接下来,我需要整理它们的区别。根据引用,主要区别可能在于目的、对象创建方式、使用阶段、透明性、接口方法以及应用场景等方面。例如,装饰模式是透明的,可以叠加使用,而代理模式可能隐藏目标对象,并且可能仅代理部分方法。 然后,我需要考虑Java中的应用实例。用户提供的示例中,装饰模式用于I/O流,如FilterInputStream,而代理模式如Spring AOP的动态代理。需要将这些例子融入回答中,以具体说明区别。 另外,用户的问题还提到了用法对比,所以需要分别说明何时使用装饰模式,何时使用代理模式,并给出实际场景。例如,装饰模式适用于需要动态添加功能的场合,代理模式适用于访问控制、延迟加载等。 最后,需要确保回答结构清晰,分点明确,并引用提供的参考资料来支持观点。同时,要避免重复,并确保语言准确,符合用户要求的格式,如使用中文,正确引用标识等。</think>在Java中,装饰模式代理模式都通过组合方式操作目标对象,但二者的设计目的实现细节存在本质差异。以下是两者的详细对比分析: --- ### 一、核心差异对比表 | 维度 | 装饰模式(Decorator) | 代理模式(Proxy) | |------------------|---------------------------------------------|-------------------------------------------| | **核心目的** | 动态添加功能(增强型扩展)[^3] | 控制对象访问(保护/延迟/远程访问等)[^4] | | **目标对象创建** | 由客户端传入(构造方法注入)[^3] | 通常由代理类内部创建(隐藏目标对象)[^3] | | **使用阶段** | 运行时动态叠加装饰 | 编译期或运行时(动态代理)确定代理关系 | | **透明性** | 对客户端透明(接口一致)[^1] | 可能不透明(隐藏目标对象状态)[^4] | | **接口方法** | 通常实现目标对象完整接口 | 可能仅代理部分方法 | | **典型应用** | Java I/O流装饰器、GUI组件增强[^1] | Spring AOP、远程方法调用、虚拟代理[^2] | --- ### 二、代码实现差异示例 #### 1. 装饰模式(以I/O流为例) ```java // 组件接口 public interface DataSource { void writeData(String data); } // 基础组件 class FileDataSource implements DataSource { public void writeData(String data) { System.out.println("写入文件: " + data); } } // 装饰器基类 abstract class DataSourceDecorator implements DataSource { protected DataSource wrappee; public DataSourceDecorator(DataSource source) { this.wrappee = source; } } // 具体装饰器:加密功能 class EncryptionDecorator extends DataSourceDecorator { public EncryptionDecorator(DataSource source) { super(source); } @Override public void writeData(String data) { wrappee.writeData(encrypt(data)); } private String encrypt(String data) { return "加密后的" + data; } } // 使用方式:动态叠加功能 DataSource source = new EncryptionDecorator(new FileDataSource()); source.writeData("敏感数据"); // 输出:写入文件: 加密后的敏感数据 ``` #### 2. 代理模式(以虚拟代理为例) ```java interface Image { void display(); } // 真实对象(延迟加载) class RealImage implements Image { private String filename; public RealImage(String filename) { this.filename = filename; loadFromDisk(); } private void loadFromDisk() { System.out.println("加载大文件: " + filename); } public void display() { System.out.println("显示图片: " + filename); } } // 代理类(控制访问) class ProxyImage implements Image { private RealImage realImage; private String filename; public ProxyImage(String filename) { this.filename = filename; } @Override public void display() { if (realImage == null) { realImage = new RealImage(filename); // 按需创建真实对象 } realImage.display(); } } // 使用方式:客户端无感知 Image image = new ProxyImage("1GB_Photo.jpg"); image.display(); // 首次调用时才加载大文件 ``` --- ### 三、关键差异点详解 1. **目标对象控制权** - 装饰器:客户端显式传递被装饰对象,可多层嵌套(如`new A(new B(new C()))`) - 代理器:代理类内部管理目标对象生命周期,客户端无法直接访问真实对象[^3] 2. **设计意图差异** - 装饰模式关注**功能增强**(如I/O流的缓冲/加密装饰)[^1] - 代理模式关注**访问控制**(如Spring AOP的权限校验、日志记录)[^2] 3. **方法覆盖范围** - 装饰器通常实现目标对象完整接口(保证透明性) - 代理器可能仅实现部分方法(如远程代理只代理远程调用相关方法)[^4] 4. **运行时行为** ```mermaid graph LR A[客户端] --> B[装饰器] B --> C[被装饰对象] D[客户端] --> E[代理] E --> F[真实对象] ``` --- ### 四、应用场景选择指南 | **场景特征** | 推荐模式 | |-------------------------------|---------------| | 需要动态叠加多个功能 | 装饰模式 | | 需要控制对象创建/访问时机 | 代理模式 | | 需要拦截特定方法(如AOP) | 动态代理[^2] | | 需要保持接口完全一致 | 装饰模式[^1] | | 需要隐藏目标对象细节 | 代理模式[^4] | --- ### 五、常见混淆场景解析 1. **日志记录功能** - 代理模式:记录方法调用信息(如Spring AOP) - 装饰模式:在原有功能基础上增加日志格式处理 2. **缓存实现** - 代理模式:实现缓存代理(如MyBatis的Mapper代理) - 装饰模式:给数据源添加缓存层(如装饰数据库连接) --- 通过理解二者的核心差异,可以更准确地选择模式。在Java生态中,装饰模式常见于I/O流处理(如`BufferedInputStream`),而代理模式广泛应用于框架级控制(如Spring的声明式事务管理)[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值