装饰模式续
Last updated
Last updated
上面的实例代码中,我们新增的功能(增加滚动条和黑色边框)都是加入到被装饰的原始类即Component的方法中,客户端并不会调用这些方法:
即经过装饰后,被装饰类只是在原有方法的内部去增强了原有方法,其实这类似于AOP的功能增强。但假如要在被装饰类中添加一个新的方法,且该方法与被装饰类中的原有方法没有任何关系,比如OA系统中,采购单(PurchaseRequest)和请假条都有display()方法,现在要对他们添加审批和删除功能,那么使用装饰模式的代码结构如下:
其中,审批装饰类代码具体如下:
这个审批功能与原始类的显示方法(display()
)没有关系,那么客户在使用Component c = new PurchaseRequest()
定义一个采购单时,由于Component
中只有display()
方法,新增的审批功能无法被调用。所以,客户端就不能使用这种面向抽象的编程方式,而必须使用PurchaseRequest request = new PurchaseRequet()
这种方式。
装饰模式的透明与半透明
构建基础构件例子中演示的装饰模式,称之为透明装饰模式。这种方式可以让客户端透明地使用装饰之前的对象和装饰之后的对象,无须关心它们的区别,此外,还可以对一个已装饰过的对象进行多次装饰,得到更为复杂、功能更为强大的对象。
OA系统例子中演示的装饰模式,称之为半透明装饰模式。半透明装饰模式可以给系统带来更多的灵活性,设计相对简单,使用起来也非常方便;但是其最大的缺点在于不能实现对同一个对象的多次装饰,而且客户端需要有区别地对待装饰之前的对象和装饰之后的对象。
为什么半透明装饰模式不能实现对同一个对象的多次装饰
如果进行多次装饰,最终功能只会增加一个,因为客户端至多能调用到最外层的那个装饰功能。
JDK中的装饰模式
JDK中最典型的装饰模式的应用就是I/O流,看如下代码:
这里,FileInputSream
相当于原始的被装饰的类,它经过了BufferedInputSream
装饰(拥有了buffer功能),又经过DataInputStream
装饰。
这里的InputStream
相当于Component
,FileInputStream
相当于ConcreteComponent
,而FilterInputStream
相当于Decorator
,BufferedInputStream
和DataInputStream
相当于ConcreteDecorator
。
输出流OutputStream与之类似。
扩展系统功能--装饰模式:文字和代码大多来自于此
《研磨设计模式 第22章 装饰模式》:JDK中装饰模式
这几个类之间的关系如下图: