当初Java刚刚推出来的时候,AWT可是一个比较热的话题,虽然现在有被Swing取代的趋势。但是我一直都觉得AWT也有其优势,至少它使用的本地代码就要比Swing快上许多,而且,可以为用户提供熟悉的本地操作系统界面。如果在Windows XP中运行基于AWT的程序的话,XP中绚烂多变的界面Theme可以轻易应用到AWT程序中,而Swing就不行了,因为AWT所调用的是本带代码,使用的是本地的窗体控件。当然,Swing也有其好处,不可一概而论。
简单来讲,AWT提供对程序员的是对窗体界面系统的抽象,而在内部实现中,针对每一种操作系统,分别有不同实现,这就是同位体(Peer)的概念。当程序员调用AWT对象时,调用被转发到对象所对应的一个Peer上,在由Peer调用本地对象方法,完成对象的显示。例如,如果你使用AWT创建了一个Menu类的实例,那么在程序运行时会创建一个菜单同位体的实例,而由创建的同位体的来实际执行菜单的现实和管理。不同的系统,有不同的同位体实现,Solaris JDK将产生一个Motif菜单的同位体,Windows下的JDK将产生一个Windows的菜单的同位体,等等。同位体的使用,使得交叉平台窗口工具的开发变得极为迅速,因为同位体的使用可以避免重新实现本地窗口控件中已经包含的方法。
图六:AWT中的组件和其对等体
实际上,从设计的角度来看,这是一个抽象和实现分离的过程--AWT是抽象,同位体是实现,抽象和实现各自成为一个对象体系,它们由一个桥连接起来,可以各自发展各自的对象层次,而不必顾虑另一方面。这就是Bridge模式所提供的思想。Bridge模式更可以提供在各个不同的实现中动态的进行切换,而不必从新编译程序。
通常,Bridge模式和AbstractFactory模式一起工作,由AbstractFactory来创建一个具体实现的对象体系。特殊的,当只有一个实现的时候,可以将Implementor抽象类去掉。这样,在抽象和实现之间建立起了一一对应的关系,但这并不损害Bridge模式的内涵。这被称为退化了的Bridge模式。
很多时候,Abstraction层次和Implementor层次之间的方法都不是一一对应的,也就是说,在Abstraction和Implementor之不是简单的的消息转发。通常,我们会将Abstraction作为一个抽象类(而不是接口)来实现。在Implementor层次中定义底层的,或者称之为原子方法,而在Abstraction层次中定义一些中高层的基于原子方法的抽象方法。这样,就能更为清晰的划分Abstraction和Implementor,类的结构也更为清晰。
图七:Bridge模式对系统的划分
下面,我们来看一个Bridge模式的具体应用。考虑这样的一个问题,需要生成一份报告,但是报告的格式并没有确定,可能是HTML文件,也可能是纯ASCII文本。报告本身也可能分为很多种,财务报表,货物报表,等等问题很简单,用继承也较容易实现,因为相互之间的组合关系并不是很多。但是,我们现在需要用Bridge的观点来看问题。
在Bridge模式中,使用一个Report类来描叙一个报告的抽象,用一个Reporter类来描叙Report的实现,它的子类有HTMLReporter和ASCIIReporter,用来分别实现HTML格式和ASCII格式的报告。在Report层次下面,有具体的一个StockListReport子类,用来表示货物清单报告。
2
3 {
4
5 Reporter reporter;
6
7 public Report(Reporter reporter) {
8
9 this.reporter = reporter;
10
11 }
12
13 //抽象类使用桥接对象的方法来实现一个任务
14
15 public void addReportItem(Object item){
16
17 reporter.addLine(item.toString());
18
19 }
20
21 public void addReportItems(List items){
22
23 Iterator iterator = items.iterator();
24
25 while ( iterator.hasNext() )
26
27 {
28
29 reporter.addLine(iterator.next().toString());
30
31 }
32
33 }
34
35 public String report(){
36
37 return reporter.getReport();
38
39 }
40
41 }
42
43 public class StockListReport extends Report{
44
45 ArrayList stock=new ArrayList();
46
47 public StockListReport(Reporter reporter){
48
49 super(reporter);
50
51 }
52
53 public void addStockItem(StockItem stockItem){
54
55 stock.add(stockItem);
56
57 addReportItem(stockItem);
58
59 }
60
61 }
62
63 //实现层次的抽象父类定义原子方法,供抽象层次的类调用
64
65 public abstract class Reporter{
66
67 String header = "";
68
69 String trailer = "";
70
71 String report = "";
72
73 public abstract void addLine(String line);
74
75 public void setHeader(String header){
76
77 this.header = header;
78
79 }
80
81 public void setTrailer(String trailer){
82
83 this.trailer = trailer;
84
85 }
86
87 public String getReport(){
88
89 return header+report+trailer;
90
91 }
92
93 }
94
95 public class HTMLReporter extends Reporter{
96
97 public HTMLReporter(){
98
99 setHeader("\n\n\n");
100
101 setTrailer("\n");
102
103 }
104
105 public void addLine(String line){
106
107 report += line + "
108
109 \n";
110
111 }
112
113 }
114
115 public class ASCIIReporter extends Reporter{
116
117 public void addLine(String line) {
118
119 report += line + "\n";
120
121 }
122
123 }
124
125
实际上,Bridge模式是一个很强大的模式,可以应用在很多方面。其基本思想:分离抽象和实现,是设计模式的基础之一。正如GOF所提到的:"找到变化的部分,并将其封装起来";"更多的考虑用对象组合机制,而不是用对象继承机制"。Bridge模式很好的体现了这几点。