设计模式之装饰器模式VS代理模式

一、装饰器模式

1、什么是装饰器模式

1) 官方定义:

	装饰器模式指的是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,
也就是装饰来包裹真实的对象。

2) 特点

(1) 装饰对象和真实对象有相同的接口。这样客户端对象就能以和真实对象相同的方式和装饰对象交互。
(2) 装饰对象包含一个真实对象的引用(reference)
(3) 装饰对象接受所有来自客户端的请求。它把这些请求转发给真实的对象。
(4) 装饰对象可以在转发这些请求以前或以后增加一些附加功能。这样就确保了在运行时,不用修改给定对象的结构就可以在外部增加附加的功能。在面向对象的设计中,通常是通过继承来实现对给定类的功能扩展。

2、怎么实现装饰器模式

装饰者模式uml.jpg
有一个接口Component,和一个已经实现了该接口的实现类:ConcreteComponent。装饰模式下,采取如下策略:
1 新建一个装饰类:Decorator,该类同样实现接口Component,保证装饰类和ConcreteComponent有一样的方法
2 同时,Decorator类内部会声明一个Component接口的实现类,并在其构造方法中,接受一个具体的Component接口的实现类,并进行初始化
3 做了以上操作之后,就可以在Decorator类中的方法里,进行相关增强操作

3、代码示例

1)Shape接口:

假设现在我们需要有一个接口Shape,里面含有一个draw方法,用来画不同类型的图。
shape接口.png

2)Circle类和Rectangle类

然后,有两个类实现该接口,分别是Circle,Rectangle。
circle.png
rectangle.png

3)抽象类ShapeDecorator

同时,有一个抽象类ShapeDecorator,作为装饰器父类
ShapeDecorator.png

4)具体的装饰类:

当需要给Circle或者Rectangle进行装饰时,选择继承ShapeDecorator类去创建一个具体的装饰类:RedShapeDecorator、ThickShapeDecorator
ThickShapeDecorator.png
RedShapeDecorator.png

5)运行Demo:

DecoratorPatternDemo.png

6)运行效果:

result.png

4、为什么用装饰器模式

装饰器模式有至少2个主要的优点:

1)比静态继承更加灵活:

与对象的静态继承相比,装饰器模式提供了更加灵活的向目标对象添加职责的方式。可以用添加和分离的方式,用装饰在运行时刻增强职责。此外,为一个特点的Component类提供多个不同的Decorator类,可以使得我们对一些职责进行混合和匹配。

2)避免在层次结构高层的类中具有太多的特征:

装饰器模式提供了一种“即用即付”的方式来添加职责,它不需要一开始就在一个复杂的、可定制的类中支持所有可预见或者不可预见的特征,只需要在有使用的必要时,定义一个Decorator去装饰这个类(逐渐添加职责)。

但是,装饰器模式也存在一些缺陷:

1)产生许多小对象:

以上述代码为例,存在两种装饰器,RedShapeDecorator和ThickShapeDecorator类,且职责单一,但倘若系统更为复杂则会衍生出十个甚至百个相似的小对象,为后期排错带来一定困难。

5、Decorator In Java

Java IO中的装饰器模式
Java IO装饰器模式.png
在所有InputStream类型的链接流处理其中,使用频率最大的就是FilterInputStream类,以这个类为抽象装饰角色的装饰模式结构非常明显和典型。以这个类为核心说明装饰模式的各个角色是由哪些流处理器扮演:
** 抽象构件(Component)角色:由InputStream扮演。这是一个抽象类,为各种子类型处理器提供统一的接口。
具体构建(Concrete Component)角色:由ByteArrayInputStream、FileInputStream、PipedInputStream以及StringBufferInputStream等原始流处理器扮演。它们实现了抽象构建角色所规定的接口,可以被链接流处理器所装饰。
抽象装饰(Decorator)角色:由FilterInputStream扮演。它实现了InputStream所规定的接口。
** 具体装饰(Concrete Decorator)角色
:由几个类扮演,分别是DateInputStream、BufferedInputStream 以及两个不常用到的类LineNumberInputStream和PushbackInputStream。

二、代理模式

1、什么是代理模式

1) 官方定义 :

为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

2) 特点:

重点在于控制对这个对象的访问,假设有一个类RealSubject,当客户端企图访问这个类的时候,只能通过new RealSubjectProxy(),间接访问RealSubject,而RealSubject的实例化则在RealSubjectProxy这个代理类的构造函数中进行。

一个代理类只能代理一个确定的类,始终强调对类的访问控制

2、如何实现代理模式

代理模式.jpg
1 有一个公共接口 Subject
2 存在一个实现公共接口Subject的类RealSubject,以及同样实现接口Subject的代理类Proxy,保证这两个类的接口方法一致。
3 同时Proxy内部持有一个Subject,并会在其构造方法中直接初始化好RealSubject这个类的实例,并在Proxy的接口方法中,调用RealSubject方法,形成代理。

3、代码示例

1)共同接口Image

Image.png

2)真实类:RealImage

RealImage.png

3)代理类:ProxyImage

ProxyImage.png

4)运行Demo

ProxyPatternDemo.png

5)运行效果

result.png

4、为何使用代理模式

为了保持行为的一致性,代理类和委托类通常会实现相同的接口,所以在访问者看来两者没有丝毫的区别。通过代理类这中间一层,能有效控制对委托类对象的直接访问,也可以很好地隐藏和保护委托类对象,同时也为实施不同控制策略预留了空间,从而在设计上获得了更大的灵活性。代理解决的问题当两个类需要通信时,引入第三方代理类,将两个类的关系解耦,让我们只了解代理类即可。
而上述例子,使用的是静态代理,一个代理类只能代理一个对象,且需要在编译期就确定,当需要为一个新类做代理时,就必须重新写一个代理类,所以,使用起来很不方便。因此利用Java反射和泛型的特点,使用动态代理会更为方便。

5、Proxy In Java

1)Java动态代理:InvocationHandler接口
2)CGLIB动态代理:MethodInterceptor接口
3)面向切面编程:AOP,在Spring中,如果Bean实现接口时,选择Java的动态代理,否则选择CGLIB进行实现。

三、装饰模式VS代理模式

1 相同点

对于装饰模式,装饰者(decorator)和被装饰者(decoratee)都实现同一个 接口
对于代理模式,代理类(proxy class)和真实处理的类(real class)都实现同一个接口

此外,不论我们使用哪一个模式,都可以很容易地在真实对象的方法前面或者后面加上自定义的方法。

2 不同点

装饰器模式关注于在一个对象上动态的添加方法。当我们使用装饰器模 式的时候,我们通常的做法是将原始对象作为一个参数传给装饰者的构造器。
代理模式关注于控制对对象的访问。用代理模式,代理类(proxy class)可以对它的客户隐藏一个对象的具体信息。因此,当使用代理模式的时候,我们常常在一个代理类中创建一个对象的实例
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值