java接口學習例子

你應該知道接口是一種契約,它與實現方式無關

但是類,即使是抽象類,你都能自定義成員變量,而成員變量往往就與實現方式有關。

這一點的實際意義不大。

但是有一點,類會暴露太多不必要,甚至不能暴露的東西,你看一下java.util中,大部分的數據結構,都被設計成了接口
-抽象類-最後實際類

例如Collection
-List
     L
-AbstractCollection
       L
-AbstractList
         L
-ArrayList

但是有一個,由於歷史原因,被設計成了類,比如Stack 
extends Vector,
你應該知道Stack的數據訪問模式,就只能是LIFO,但是Vector是一個List,可以隨機訪問,可以任意增減。

結果Stack s 
= new Stack();

不光能夠pop
/push/peer還能add,get,set,remove

如果你用一個接口IStack 裏面只有pop
/push/peer方法,然後仍然通過繼承Vector的方式實現,

IStack s 
= new MyStack();

此時,就無法add,get,set,remove

舉個生動一點的例子

public interface BritishSpy {
  
public String speak(); //英國間諜講英語
}


public interface GermanSpy {
  
public String sprechen(); //德國間諜講德語
}


public class DoubleAgent implements BritishSpy, GermanSpy {
  
public String speak() return "Hello"; }
  
public String sprechen() return "Gutentag"; }
}


public class Agency {
  
public static void toMI5(BritishSpy spy) {
    
//軍情5處當然只能說英語,做英國間諜
    spy.speak();
    
//spy.sprechen();不可見
  }


  
public static void inGermany(GermanSpy spy) {
    
//spy.speak();不可見
    spy.sprechen();
  }


  
public static void main(String[] args) {
    DoubleAgent da 
= new DoubleAgent();
    BritishSpy es 
= (BritishSpy) da;
    GermanSpy gs 
= (GermanSpy) da;
    toMI5(da); 
//MI5也不知道他是一個雙重間諜,只知道他是BritishSpy
    toMI5(es); //更安全
    
//toMI5(gs); 不可能
    inGermany(da); //在德國還是安全的,德國人不知道他的雙重間諜身份,只知道他是GermanSpy
    inGermany(gs); 
    
//inGermany(es); 不可能
  }

}


假設你只用class,因爲不能多重繼承,所以,speak()
/sprechen()比然聲明在同一個class裏面


public abstract class DoubleAgent extends Spy/**(略...)*/ {
  
public abstract String speak();
  
public abstract String sprechen();
}


public class PoorDoubleAgent {
  
public String speak() return "Hello"; }
  
public String sprechen() return "Gutentag"; }
}


晚了,不管你PoorDoubleAgent a 
= new PoorDoubleAgent();還是DoubleAgent a = new PoorDoubleAgent();,全世界都知道他是一個雙重間諜,他到哪裏都必死無疑
前面舉了一個關於“安全性”方面的例子

接口只暴露給對方(比如Agent的軍情5處方法)它所需要的足夠信息,其他無關的,甚至有害的信息不會暴露給對方。因爲,我傳給你的是接口類型,我除了是這個接口(和這個接口的父接口,inteface A 
extends B, C)的實例外,你頂多知道我是一個Object(不是int:P),其他的姓甚名誰,哪裏住址,父母安好,兄妹幾何都與你無關,我們只需要關心我們簽訂的合同(接口)

再舉一個有關靈活性方面的例子

假設某公司已經有一個更新過N代的,邏輯複雜無比
public class A extends B /** where b extends c, c extends d and so on... */ {
  
public void init() {...}
  
public void release() {...}
  
public String doXXX() {...}
  
public String doYYY() {...}
}


而這個A又被很多類繼承或使用,doXXX
/doYYY 方法已經無法更改

假設現在這個公司要參加某個標準化組織,而這個組織要求所有提供這樣的方法

String getXXX(); String getYYY();

加入用接口標準化組織只要規定成員們都實現
public interface IBusiness {
  String getXXX(); 
  String getYYY();
}

而這個公司只需要稍微改寫一點點即可
public class A extends B /** where b extends c, c extends d and so on... */ 
  
implements IBusiness {
  
public String getXXX() return doXXX(); }
  
public String getYYY() return doYYY(); }

//保留
  public void init() {...}
  
public void release() {...}
  
public String doXXX() {...}
  
public String doYYY() {...}
}


這樣既滿足了標準化的要求,又滿足了無需修改原來繼承A或者使用A的無數個class(有些可能在用戶那裏,不可能更改)

假如不用接口,你有兩個選擇:數典忘祖或者自絕於人

數典忘祖:
你的新A必須繼承標準化組織的Business,原來a,b, c d...裏面的代碼全部得重新組織到這個新的A裏面,與此同時,那些調用或者繼承A的class難保不需要重寫

自絕於人
原來的就讓它去,誰也別再提它了,我們以後就用新的NewA,結果,你的新客戶倒是滿足了標準化,你的老客戶可就 :
< :@ :$,而且以後需要維護A和NewA
定義接口:
interface Fight{
    
void fight();
}


肥肥和瘦瘦去實現這個接口:
class FatFat implements Fight{
    
public void fight(){
        System.out.println(
"FatFat 打人很痛!");
    }

}


class ThinThin implements Fight{
    
public void fight(){
        System.out.println(
"ThinThin 打人一點都不痛!!哈哈。");
    }

}


然後你可能會這另一個類中使用到FatFat和ThinThin的對象,然後都去執行fight,但是你可能不到運行時就不會知道是具體的那個類的對象,這是你就感謝他們都實現了Fight接口,你可以向上轉型,然後通過運行時的多態產生你想要的行爲。

Fight a
=new FatFat();
Fight b
=new ThinThin();
a.fight();
b.fight();
這樣就會執行不同的動作。

或者如果你有一個方法
f(Fight i)
{
   i.fight();
}


如果c是實現了Fight接口的其中一個類,那麼你就可以這樣使用這個方法:
f(c);
你不需要知道c究竟是什麼對象(不管是FatFat還是ThinThin),你都可以得到你想要的fight動作。


 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章