选择下列产品马上在线沟通
服务时间:9:30-18:00
摘要
本文描述了Decorator模式的三种不同实现:继承、封装与外挂。深入讨论了每一种实现方式的优点与不足。原文链接:
Three approaches for decorating your code
每一们读过GoF的那本著名的设计模式一书的人都会知道Decorator模式。现在,让我们暂时忘记所了解的Decorator概念,尝试着从我们的开发经验中去理解Decorator模式吧。Decorator是用于装饰一个事物(或人)的另一个事物(或人)。一个Decorator直接改变被装饰对象的职责或特征,但是不能改变被装饰对象的自有属性。例如:一个镜框可以装饰图片,化妆品可以装饰女孩的脸等等。从我们的专业角度来讨论一些存在的实例:1 JScrollPane可以装饰JComponent的视图部分。JComponent本身并不会被改变,但是增加了一个新的属性(可滚动)。2 BufferedInputStream是InputStream的装饰子,本身BufferedInputStream就是一个InputStream,但是它更快,因为提供了对数据的缓存。3 考虑一下DebugButton,它与JButton一样,但是它在被点击时可以向日志文件添加消息。DebugButton是JButton的装饰子,因为它直接改变了JButton但并没有改变它的自有属性。4 再又如ScrollOverButton,它增加了一个鼠标滑过的行为。当鼠标移出时它是平的,当鼠标经过时它具有一个凸起的边框。很显然,ScrollOverButton也是JButton的装饰子。现在,我们知道Decorator可能有三种不同的实现:1 继承(Inheritance)2 封装(Wrapper)3 外挂(External)本文将讨论每一个实现模型,以及它们的优缺点。
继承
对于开发人员而言,最直观的Decorator实现就是:写一个派生类,它继承自被装饰类,并赋于新的职责。新的职责可以是通过增加方法或是修改已有方法来实现。public class DebugButton extends JButton{ public DebugButton() { addActionListener(new ActionListener() { System.out.println("debug message"); }); }}此外,我们也可以用相同的方式来实现ScrollOverButton:不是增加ActionListener,而是增加MouseListener。在MouseListener回调方法中改变JButton的边框,当mouseEntered()被调用时,将边框从EmpetyBorder变为RaisedBevelBorder。而当mouseExited()方法被调用时,再将边框从RaisedBevelBorder恢复成EmpetyBorder。对于BufferedInputStream,同样实现也是非常简单的。修改每个读数据的方法,让它从内存缓冲区来读取数据。如果缓冲区是空的,它可以通过super.read()方法来获取数据并填充缓冲区。JScrollPane,要实现起来就有点复杂,下面我将讨论为什么它会比较难以用继承的方式来实现。讨论一下继承方式实现Decorator模式的优点与缺点: