JAVA在設(shè)計(jì)接口和類(lèi)的規(guī)則時(shí),有一個(gè)明確的規(guī)定。JAVA不支持類(lèi)(實(shí)現(xiàn))的多重繼承,但支持接口(定義)的多重繼承。
我已經(jīng)無(wú)從了解這個(gè)設(shè)計(jì)的初衷,但這樣的規(guī)定隱含了以下的意義。
接口是設(shè)計(jì)的產(chǎn)物,即在需求設(shè)計(jì)時(shí)定義的對(duì)軟件功能的定義。而類(lèi)是實(shí)現(xiàn)的產(chǎn)物,它是在實(shí)現(xiàn)過(guò)程中根據(jù)實(shí)現(xiàn)的具體情況而完成的。如果用代碼來(lái)說(shuō)明就是:
在設(shè)計(jì)時(shí)我需要我設(shè)計(jì)的“模塊”提供兩個(gè)功能:
1.提供兩個(gè)整數(shù)相加的功能。
2.提供兩個(gè)字符串連接的功能。
我是一個(gè)偉大的設(shè)計(jì)師,為了不影響我的整體思路,我不會(huì)在這時(shí)停下來(lái)去實(shí)現(xiàn)它,所以我需要一個(gè)類(lèi)似偽代碼的東西來(lái)記錄我的實(shí)現(xiàn)思路。java說(shuō),好,我們?yōu)槟闾峁┮粋€(gè)叫接口的東西,你只寫(xiě)下你要實(shí)現(xiàn)的東西不用提供具體實(shí)現(xiàn)方法。
- interface IMyFunc {
-
- public int add(int a, int b);
-
- public String concat(String str1, String str1);
- }
。。。。。。。其它設(shè)計(jì)。
好了,哪個(gè)小匪來(lái)領(lǐng)實(shí)現(xiàn)這個(gè)任務(wù)?
小匪甲領(lǐng)取了這個(gè)編碼任務(wù)。分析大當(dāng)家的設(shè)計(jì)思想,啊這個(gè)好辦。
- class MyMathImp implements IMyFunc{
-
- public int add(int n1,int n2) {
-
- //因?yàn)閭鬟M(jìn)來(lái)的都是整數(shù),如果不是整數(shù)在編譯時(shí)就出錯(cuò)了,
- //所以我不用檢查,直接的相加,哈哈,今天工資混到手了。
-
- return n1 + n2;
-
- }
-
-
-
- public String concat(String s1,Strings2) {
-
- //哎,這個(gè),這個(gè)好象要檢查一下吧,如果有一個(gè)字符串是null,
- //我是顯示"字符串null"還是顯示"字符串"呢?如果兩個(gè)都為null,
- //我是顯示一個(gè)"null"還是顯示"nullnull"呢?
- //真復(fù)雜,嚴(yán)密性比具體實(shí)現(xiàn)還復(fù)雜,我干脆把它放到另一個(gè)方法中吧。
-
- return checkedConcat(s1,s2);
- }
-
- String checkedConcat (String s1,String s2){
- if(s1 == null && s2 == null) return "null";
- if(s1 == null) s1 = "null";
- if(s2 == null) s2 = "null";
- return s1 + s2;
- }
-
- }
checkedConcat我還想被別的地方調(diào)用,所以我不想設(shè)計(jì)成ptivate的。所以我設(shè)計(jì)的MyModuleImp從外面可以看到三個(gè)方法。
大當(dāng)家的叫我提供兩個(gè)方法,而我的實(shí)現(xiàn)有三個(gè)方法,幸虧有接口啊,我發(fā)布這個(gè)模塊時(shí)只提供接口的文檔。這樣你在智能感應(yīng)的IDE中一打開(kāi)這個(gè)接口看到的只是大當(dāng)家定義的兩個(gè)方法。
所以:接口可以只將設(shè)計(jì)意圖的方法暴露給調(diào)用者。
那么,當(dāng)我一個(gè)類(lèi)提供了不同功能的方法時(shí),我想在不同時(shí)候只顯示某類(lèi)功能的方法,怎么辦?
其實(shí)這個(gè)問(wèn)題Sun的代碼中都沒(méi)有很好地處理。比如我的一個(gè)類(lèi)提供了對(duì)象的初始化方法和對(duì)象釋放的方法,整數(shù)運(yùn)算的方法和字符串運(yùn)算方法以及圖形運(yùn)算方法。當(dāng)然這只是舉例。
有人說(shuō)這個(gè)類(lèi)設(shè)計(jì)不合理,這么多不同類(lèi)型的功能應(yīng)該在不同類(lèi)中實(shí)現(xiàn)。
說(shuō)得對(duì)!但是..........
如果我們的對(duì)象是本地生成的,多次new多個(gè)對(duì)象成本不是太高,如果我們的對(duì)象是從遠(yuǎn)程調(diào)用的,那么多個(gè)對(duì)象的生成成本就很高了。
另外任何對(duì)象自身管理的方法和業(yè)務(wù)方法不能分到兩個(gè)類(lèi)中實(shí)現(xiàn)吧?一個(gè)只有自身管理的方法的類(lèi)除了自戀還有什么用?而有些必須要被始化和釋放等管理的 對(duì)象只有業(yè)務(wù)方法它也工作不起來(lái),所以至少有兩類(lèi)功能要在同一類(lèi)中完成。假如它們的重載方法足夠多時(shí),你會(huì)看到它們是很多功能的方法按字母排序混合在一 起。
典型的就是URLConnection類(lèi),你打開(kāi)它時(shí),設(shè)置請(qǐng)求參數(shù)的方法,獲取響應(yīng)頭域的方法,獲取輸入輸出的方法一大堆。不過(guò)還好是它們的命名方式使很多功能相同的方法能排在一起。
如何有效的組織一個(gè)實(shí)現(xiàn)的不同功能的方法的分類(lèi)?我們可以通過(guò)多接口來(lái)完成。
這個(gè)思想早在COM時(shí)代就已經(jīng)采用了,無(wú)論你獲取的是IUnKnown接口還是IDispatch接口還是業(yè)務(wù)接口,其實(shí)反回的都是同一個(gè) CoClass對(duì)象,但你獲取不同接口看到的是不同功能的函數(shù)。同時(shí)你只要實(shí)例化一次,獲取到任何接口就可以從這一接口生成其它接口,這對(duì)于調(diào)用者是非常 有意義的,我不僅能得到不同功能的函數(shù)分類(lèi),而且不需要多次實(shí)例化多個(gè)對(duì)象。
- interface IMath {
-
- public int add(int a, int b);
-
- public int mul(int a, int b);
- }
-
- interface IStrUtil {
-
- public String concat(String s1, String s2);
-
- public String Upper(String s1);
-
- }
-
- interface IObjManager {
-
- void init();
-
- void destory();
-
- }
-
- class MyModuleImp implements IMath, IStrUtil, IObjManager {
-
- public int add(int a, int b) {
- return a + b;
- }
-
- public int mul(int a, int b) {
- return a * b;
- }
-
- public String concat(String s1, String s2) {
- return checkedConcat(s1, s2);
- }
-
- public String Upper(String s1) {
- return checkedUpper(s1);
- }
-
- public void init() {
- System.out.println("init.........");
- }
-
- public void destory() {
- System.out.println("destory.........");
- }
-
- String checkedConcat(String s1, String s2) {
-
- if (s1 == null && s2 == null)
- return "null";
- if (s1 == null) s1 = "null";
- if (s2 == null) s2 = "null";
- return s1 + s2;
- }
-
- String checkedUpper(String s1) {
-
- if (s1 == null) return null;
- return s1.toUpperCase();
- }
- }
OK!
IObjManager om = new MyModuleImp(); //或getObjFromNet如果我們把生成實(shí)例的方法統(tǒng)一封裝起來(lái),以及對(duì)象的生命周期管理都規(guī)定在一個(gè)類(lèi)似IUnknown的接口中,我們就可以 把多功能的不同類(lèi)有一個(gè)統(tǒng)一的管理行為,就象遠(yuǎn)程EJB對(duì)象的實(shí)例化。
om. 這時(shí)我們看到的只是IObjManager接口的方法,我們可以init.destory.
當(dāng)我們需要它的業(yè)務(wù)方法時(shí):
IMath m = (IMath)om; //相當(dāng)于QueryInterface
m. 這時(shí)我們看到的只是math相關(guān)的功能方法。
另外當(dāng)我們想增加一個(gè)方法并保留原有方法時(shí)只需在新的接口中聲明,并讓實(shí)現(xiàn)類(lèi)繼承自這個(gè)接口(其實(shí)就是在implements關(guān)鍵字后面加上接口名稱(chēng))。這樣新舊接口可以并存使用,既不影響以前的代碼,也不影響后來(lái)的人使用新接口:
- interface IMathEx{
-
- public int add(int a, int b);
-
- public int mul(int a, int b);
-
- public double sqrt(double a);
-
- }
-
-
-
- class MyModuleImp implements IMath,IMathEx, IStrUtil, IObjManager{
-
- //增加public double sqrt(double a)的實(shí)現(xiàn)
-
- }
這樣原來(lái)使用IMath來(lái)計(jì)算“加和乘“的代碼根本不受影響,而新的程序可以使用IMathEx來(lái)計(jì)算“加,乘和開(kāi)方”運(yùn)算。
所以多接口不僅使我們能夠有效的組織不同功能的代碼,而且可以使對(duì)象具有統(tǒng)一的管理方法,同時(shí)避免多次生成對(duì)象帶來(lái)的開(kāi)銷(xiāo)。