修饰者的静态和动态特性
工程学上经常提到静态和动态的概念。静态方法研究那些变化或位移相对较小的对象,例如桥梁或建筑,而动态方法研究那些变化和移动较快的对象,例如发动机。在软件工程中也有相应的概念,静态方法研究在编译时类之间的关系,而动态方法研究在运行时类参与的一些的事件。在这一节中,我将用UML类图来展示修饰者的静态特性,用UML时序图来展示修饰者的动态特性。
修饰者的静态特性
修饰者通过增加功能来修饰被修饰对象(Decorated,也就是真实对象)。下面的UML类图展示了修饰者和真实对象之间的关系。
修饰者继承了被修饰者或者实现了被修饰者的接口,同时修饰者还保存了对被修饰者实例的引用,这个实例就是修饰者修饰的对象。为了说明这些类在到底是如何关联的,图2中举了一个Java SDK的java.io.package中的实际例子。
BufferedReader和FilterReader就是图1中演示的抽象类,他们都继承了抽象类Reader,并且将方法调用传递给Reader对象。由于继承了修饰者类,因此LineNumberReader和PushbackReader也是修饰者类。
修饰者的动态特性
在运行时,修饰者将方法调用传递给被修饰者,如图3所示:
修饰者通常将对被修饰者的调用包装起来,图3描述了这种特性。图4描述了上面的I/O例子中修饰者的动态特性:
现在大家对修饰模式以及它的静态和动态特性有一个比较明确的认识了。让我们通过一个完整的例子来说明如何在代码中实现修饰模式。
排序和过滤修饰
修饰者主要是用于给被修饰者增加功能。在下面的例子中,我们会给Swing中的表增加排序和过滤的功能。在介绍例子之前,先简单介绍一下如何使用Swing中的JTable类。
import javax.swing.*;
import javax.swing.table.*;
public class Test extends JFrame
{
public static void main(String args[])
{
Test frame = new Test();
frame.setTitle("Swing表的例子");
frame.setBounds(300, 300, 450, 300);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.show();
}
public Test()
{
TableModel model = new TestModel();
getContentPane().add(new JScrollPane(new JTable(model)));
}
private static class TestModel extends AbstractTableModel
{
final int rows = 100, cols = 10;
public int getRowCount() {
return rows;
}
public int getColumnCount() {
return cols;
}
public Object getValueAt(int row, int col) {
return "(" + row + "," + col + ")";
}
}
}
该程序创建了一个100×10的表。表对象由三个部分组成:表模型、视图和事件控制器。表中的数据保存在表模型中,视图控制数据的显示,而事件控制器控制对事件的响应。图5是运行这个程序的结果。
图5 Swing表的例子
排序修饰者
图6中的应用程序包含了一张两列的表,一列是货物名称,一列是价格。通过单击列头可以根据货物的价格对表进行排序。下面是这个程序的代码:
图6 排序修饰者的例子
(未完待续)