在Java中,什么时候该用抽象类,什么时候该用接口?下面的文章将通过实例,而不是从理论的角度给你一个清晰的回答,让你有可能获得醍醐灌顶般的彻悟。以下是原文翻译。
针对2001年4月的 "抽象类和接口" 一文,读者给予了积极的反馈。
其中经常提到的一个要求是,希望能够提供一个完整的例子,来说明到底该如何使用接口(interface)和抽象类(abstract class)。看来,我上次的回答过于理论化了。所以,在本次Java Q&A专题中,我将通过一个使用了接口和抽象类的程序实例,将这一讨论继续深化。
进行网络通信编程时,大家会发现,通信往往是通过 "成对的键和值" (key/value pair,以下称为 "键/值对")的传输来完成的。HTTP POST和HTTP GET都采用了 "键/值对" 通信。和webMethod这样的EAI服务器通信,"键/值对" 通信也是一种选择的机制。甚至在使用Java特性时也可以看到 "键/值对"。中国自学编程编程网整理发布,"键/值对" 无处不在。
"键/值对" 通信之所以常见,在于它可以通过简单的机制赋予数据以含义。虽然简单,但对于每种协议来说,将 "键/值对" 数据放到线路上的方式却各不相同。如果想和Web服务器通信,你会使用URLConnection来和服务器进行HTTP连接。其它类型的通信则需要你使用其它某种方式。本专题中,我将演示如何使用接口和抽象类来生成一个程序框架,使得这个程序可以和任何支持 "键/值对" 消息的服务器通信。
对"键/值对" 通信可以提取两种抽象。
第一,传送给接收者的 "键/值对" 数据构成一条Message。
第二,消息是通过某种协议传送给服务器的。可以将这种协议抽象为MessageBus。所以,假如要和Web服务器通信,可以通过HTTP MessageBus传送消息。
被传送的消息以及传送消息的机制会经常变化,至少不同程序之间是这样。当你确信某个东西会经常发生变化时,它就是接口的最好选择。
下面一一分析我们的消息发送程序所需要的各个接口。
MessageBus
从下面的代码可以看到,MessageBus知道它能够将一个二维数组类型的 "键/值对" 传送给某个接收者。但要注意,这个接口并没有说如何传送或者传送给谁。相反,这些细节留给了实现这个接口的类:
public interface MessageBus {
public String sendMessage( String [][] values ) throws BusException;
}
这个接口使用起来功能十分强大。你可以用URLConnections来实现它,以进行HTTP通信;也可以通过socket,用自定义协议来实现它;你甚至可以只是将数据记录到普通文件或数据库中。
总之,这个接口允许你建立多种不同的实现。更进一步来说,采用接口而不是某个特定的实现来进行编程,你就能够尽享多态所带来的好处,可以在你的程序中随意更换各种不同的实现。
举例来说,当想调试程序时,你可以将一个 "HTTP MessageBus实现" 替换成一个 "通信记录实现"。这种方法使得你可以轻松地改变程序的工作方式,而无需对原始程序做大量的修改。任何时候需要支持一种新的通信方式,只需简单地建立一个新的MessgaeBus实现就可以了。
Message
下面的示例代码中,Message只知道可以通过MessageBus将自己传送出去。它的具体实现才会去考虑如何得到Message的值。
注意:你不可能找到一个用于获得Message值的函数。相反,我们让Message完全包装它的数据,并且相信它可以将自己正确地放到MessageBus上:
public interface Message {
public String send( MessageBus mb ) throws BusException;
}