Java SE 7 技術手冊第七章草稿 - 何謂介面?

15
Java SE 7 7.1 何謂介面 何謂介面 何謂介面 何謂介面? 6 章談過繼承,但你也許在一些書或文件中看過「別濫用繼承」,或者「優先 考慮介面而不是用繼承」的說法,什麼情況叫濫用繼承?介面代表的又是什麼?這一 節將實際來看個海洋樂園遊戲,探討看看如何設計與改進,瞭解繼承、介面與多型的 用與不用之處。 7.1.1 介面定義行為 介面定義行為 介面定義行為 介面定義行為 老闆今天想開發一個海洋樂園遊戲,當中所有東西都會游泳。你想了一下,談到 會游的東西,第一個想到的就是魚,上一章剛學過繼承,也知道繼承可以運用多型, 你也許會定義 Fish 類別中有個 swim()的行為: public abstract class Fish { protected String name; public Fish(String name) { this.name = name; } public String getName() { return name; } public abstract void swim(); } 由於實際上每種魚游泳方式不同,所以將 swim()定義為 abstract ,因此 Fish 也是 abstract。接著定義小丑魚繼承魚: public class Anemonefish extends Fish { public Anemonefish(String name) { super(name); } @Override public void swim() { System.out.printf(" %s %n", name); } } Anemonefish 繼承了 Fish ,並實作 swim()方法,也許你還定義了鯊魚 Shark 類別繼承 Fish、食人魚 Piranha 繼承 Fishpublic class Shark extends Fish { public Shark(String name) { super(name);

description

Java SE 7 技術手冊

Transcript of Java SE 7 技術手冊第七章草稿 - 何謂介面?

Page 1: Java SE 7 技術手冊第七章草稿 - 何謂介面?

Java SE 7技術手冊草稿

7.1 何謂介面何謂介面何謂介面何謂介面???? 第 6 章談過繼承,但你也許在一些書或文件中看過「別濫用繼承」,或者「優先

考慮介面而不是用繼承」的說法,什麼情況叫濫用繼承?介面代表的又是什麼?這一

節將實際來看個海洋樂園遊戲,探討看看如何設計與改進,瞭解繼承、介面與多型的

用與不用之處。

7.1.1 介面定義行為介面定義行為介面定義行為介面定義行為

老闆今天想開發一個海洋樂園遊戲,當中所有東西都會游泳。你想了一下,談到

會游的東西,第一個想到的就是魚,上一章剛學過繼承,也知道繼承可以運用多型,

你也許會定義 Fish類別中有個 swim()的行為:

public abstract class Fish {

protected String name;

public Fish(String name) {

this.name = name;

}

public String getName() {

return name;

}

public abstract void swim();

}

由於實際上每種魚游泳方式不同,所以將 swim()定義為 abstract,因此 Fish

也是 abstract。接著定義小丑魚繼承魚:

public class Anemonefish extends Fish {

public Anemonefish(String name) {

super(name);

}

@Override

public void swim() {

System.out.printf("小丑魚 %s 游泳%n", name);

}

}

Anemonefish繼承了 Fish,並實作 swim()方法,也許你還定義了鯊魚 Shark

類別繼承 Fish、食人魚 Piranha繼承 Fish:

public class Shark extends Fish {

public Shark(String name) {

super(name);

Page 2: Java SE 7 技術手冊第七章草稿 - 何謂介面?

Java SE 7技術手冊草稿

}

@Override

public void swim() {

System.out.printf("鯊魚 %s 游泳%n", name);

}

}

public class Piranha extends Fish {

public Piranha(String name) {

super(name);

}

@Override

public void swim() {

System.out.printf("食人魚 %s 游泳%n", name);

}

}

老闆說話了,為什麼都是魚?人也會游泳啊!怎麼沒寫?於是你就再定義 Human

類別繼承 Fish...等一下!Human 繼承 Fish? 不會覺得很奇怪嗎?你會說程式沒

錯啊!編譯器也沒抱怨什麼!

對!編譯器是不會抱怨什麼,就目前為止,程式也可以執行,但是請回想上一章

曾談過,繼承會有是一種是一種是一種是一種((((is-a))))的關係,所以 Anemonefish是一種 Fish,Shark

是一種 Fish,Piranha是一種 Fish,如果你讓 Human繼承 Fish,那 Human是

一種 Fish?你會說「美人魚啊!」...@#$%^&

圖圖圖圖 7.1 繼承會有繼承會有繼承會有繼承會有 is-a關係關係關係關係

提示提示提示提示 圖 7.1中 Fish是斜體字,表示是抽象類別,而 swim()是斜體字,表示

是抽象方法,name旁邊有個#,表示為 protected。

Page 3: Java SE 7 技術手冊第七章草稿 - 何謂介面?

Java SE 7技術手冊草稿

程式上可以通過編譯也可以執行,但邏輯上或設計上有不合理的地方,你可以繼

續硬掰下去,如果現在老闆說加個潛水航呢?寫個 Submarine 繼承 Fish 嗎?

Submarine 是一種 Fish 嗎?繼續這樣的想法設計下去,你的程式架構會越來越不

合理,越來越沒有彈性!

記得嗎?Java中只能繼承一個父類別,所以更強化了「是一種」關係的限制性。

如果今天老闆突發奇想,想把海洋樂園變為海空樂園,有的東西會游泳,有的東西會

飛,有的東西會游也會飛,如果用繼承方式來解決,寫個 Fish讓會游的東西繼承,

寫個 Bird 讓會飛的東西繼承,那會游也會飛的怎麼辦?有辦法定義個飛魚

FlyingFish同時繼承 Fish跟 Bird嗎?

重新想一下需求吧!老闆今天想開發一個海洋樂園遊戲,當中所有東西都會游

泳。「所有東西」都會「游泳」,而不是「某種東西」都會「游泳」,先前的設計方式

只解決了「所有魚」都會「游泳」,只要它是一種魚(也就是繼承 Fish)。

「所有東西」都會「游泳」,代表了「游泳」這個「行為」可以被所有東西擁有,

而不是「某種」東西專屬,對於「定義行為」,在 Java中可以使用 interface關鍵

字定義:

OceanWorld1 Swimmer.java

package cc.openhome;

public interface Swimmer {

public abstract void swim();

}

以下程式碼定義了 Swimmer 介面,介面僅用於定義行為,所以 Swimmer 中的

swim()方法不能實作,直接標示為 abstract,而且一定是 public。物件若想擁

有 Swimmer定義的行為,就必須實作 Swimmer介面。例如 Fish擁有 Swimmer行

為:

OceanWorld1 Fish.java

package cc.openhome;

public abstract class Fish implements Swimmer {

protected String name;

public Fish(String name) {

this.name = name;

}

public String getName() {

return name;

}

@Override

public abstract void swim();

Lab

Lab

Page 4: Java SE 7 技術手冊第七章草稿 - 何謂介面?

Java SE 7技術手冊草稿

}

類別要實作介面,必須使用 implements 關鍵字,實作某介面時,對介面中定

義的方法有兩種處理方式,一是實作介面中定義的方法,而是再度將該方法標示為

abstract。在這個範例子中,由於 Fish並不知道每條魚怎麼游,所以使用第二種

處理方式。

目前 Anemonefish、Shark與 Piranha繼承 Fish後的程式碼如同先前示範

的片段,無需修改。那麼,如果 Human要能游泳呢?

OceanWorld1 Human.java

package cc.openhome;

public class Human implements Swimmer {

private String name;

public Human(String name) {

this.name = name;

}

public String getName() {

return name;

}

@Override

public void swim() {

System.out.printf("人類人類人類人類 %s 游泳游泳游泳游泳%n", name);

}

}

Human 實作了 Swimmer,不過這次 Human 可沒有繼承 Fish,所以 Human 不

是一種 Fish。類似地,Submarine也有 Swimmer的行為:

OceanWorld1 Submarine.java

package cc.openhome;

public class Submarine implements Swimmer {

private String name;

public Submarine(String name) {

this.name = name;

}

public String getName() {

return name;

}

Lab

Lab

Page 5: Java SE 7 技術手冊第七章草稿 - 何謂介面?

Java SE 7技術手冊草稿

@Override

public void swim() {

System.out.printf("潛水艇潛水艇潛水艇潛水艇 %s 潛行潛行潛行潛行%n", name);

}

}

Submarine 實作了 Swimmer,不過 Submarine 沒有繼承 Fish,所以

Submarine不是一種 Fish。目前程式的架構如下:

圖圖圖圖 7.3 運用介面改進程式架構運用介面改進程式架構運用介面改進程式架構運用介面改進程式架構

提示提示提示提示 圖 7.3中的虛線空心箭頭表示實作介面。

以以以以 Java的語意來說的語意來說的語意來說的語意來說,,,,繼承會有繼承會有繼承會有繼承會有「「「「是一種是一種是一種是一種」」」」關係關係關係關係,,,,實作介面則表示實作介面則表示實作介面則表示實作介面則表示「「「「擁有行為擁有行為擁有行為擁有行為」」」」,,,,

但不會有但不會有但不會有但不會有「「「「是一種是一種是一種是一種」」」」的關係的關係的關係的關係。Human與 Submarine實作了 Swimmer,所以都擁有

Swimmer定義的行為,但它們沒有繼承 Fish,所以它們不是一種魚,這樣的架構比

較合理也較有彈性,可以應付一定程度的需求變化。

提示提示提示提示 有些書或文件會說,Human與 Submarine是一種 Swimmer,會有這種

說法的作者,應該是有 C++程式語言的背景,因為 C++中可以多重繼承,

也就是子類別可以擁有兩個以下的父類別,若其中一個父類別用來定義

為抽象行為,該父類別的作用就類似 Java中的介面,因為也是用繼承語

Page 6: Java SE 7 技術手冊第七章草稿 - 何謂介面?

Java SE 7技術手冊草稿

意來實作,所以才會有是一種的說法。

由於 Java只能繼承一個父類別,所以「是一種」的語意更為強烈,我建

議將「是一種」的語意保留給繼承,對於介面實作則使用「擁有行為」

的語意,如此就不會搞不清楚類別繼承與介面實作的差別,對於何時用

繼承,何時用介面也比較容易判斷。

7.1.2 行行行行為為為為的多型的多型的多型的多型

在 6.1.2曾試著當編譯器,判斷哪些繼承多型語法可以通過編譯,加入扮演(Cast)

語法的目的又是為何,以及哪些情況下,執行時期會扮演失敗,哪些又可扮演成功。

會使用介面定義行為之後,也要再來當編譯器,看看哪些是合法的多型語法。例如:

Swimmer swimmer1 = new Shark();

Swimmer swimmer2 = new Human();

Swimmer swimmer3 = new Submarine();

這三行程式碼都可以通過編譯,判斷方式是「右邊是不是擁有左邊的行為」,或

「是右邊物件是不是實作了左邊介面」。

圖圖圖圖 7.4 是否擁有行為是否擁有行為是否擁有行為是否擁有行為????是否實作介面是否實作介面是否實作介面是否實作介面????

Shark擁有 Swimmer行為嗎?有的!因為 Fish實作了 Swimmer介面,也就

是 Fish擁有 Swimmer行為,Shark繼承 Fish,當然也擁有 Swimmer行為,所以

通過編譯,Human與 Submarine也都實作了 Swimmer介面,所以通過編譯。

更進一步地,來看看底下的程式碼是否可通過編譯?

Swimmer swimmer = new Shark();

Shark shark = swimmer;

第一行要判斷 Shark 是否擁有 Swimmer 行為?是的!可通過編譯,但第二行

呢?swimmer是 Swimmer型態,編譯器看到該行會想到,有 Swimmer行為的物件

是不是 Shark呢?這可不一定!也許實際上是 Human實例!因為有 Swimmer行為

的物件不一定是 Shark,所以第二行編譯失敗!

Page 7: Java SE 7 技術手冊第七章草稿 - 何謂介面?

Java SE 7技術手冊草稿

就上面的程式碼片段而言,實際上 swimmer是參考至 Shark實例,你可以加上

扮演(Cast)語法:

Swimmer swimmer = new Shark();

Shark shark = (Shark) swimmer;

對第二行的語意而言,就是在告訴編譯器,對!你知道有 Swimmer行為的物件,

不一定是 Shark,不過你就是要它扮演 Shark,所以編譯器就別再囉嗦了。可以通

過編譯,執行時期 swimmer確實也是參考 Shark實例,所以也沒有錯誤。

底下的程式片段會在第二行編譯失敗:

Swimmer swimmer = new Shark();

Fish fish = swimmer;

第二行 swimmer是 Swimmer型態,所以編譯器會問,實作 Swimmer介面的物

件是不是繼承 Fish?不一定,也許是 Submarine!因為會實作 Swimmer介面的並

不一定繼承 Fish,所以編譯失敗了。如果加上扮演語法:

Swimmer swimmer = new Shark();

Fish fish = (Fish) swimmer;

第二行告訴編譯器,你知道有 Swimmer 行為的物件,不一定繼承 Fish,不過

你就是要它扮演 Fish,所以編譯器就別再囉嗦了。可以通過編譯,執行時期 swimmer

確實也是參考 Shark實例,它是一種 Fish,所以也沒有錯誤。

下面這個例子就會拋出 ClassCastException錯誤:

Swimmer swimmer = new Human();

Shark shark = (Shark) swimmer;

在第二行,swimmer實際上參考了Human實例,你要他扮演鯊魚?這太荒繆了!

所以執行時就出錯了。類似地,底下的例子也會出錯:

Swimmer swimmer = new Submarine();

Fish fish = (Fish) swimmer;

在第二行,swimmer 實際上參考了 Submarine 實例,你要他扮演魚?又不是

在演哆啦 A 夢中海底鬼岩城,哪來的機器魚情節!Submarine 不是一種 Fish,執

行時期會因為扮演失敗而拋出 ClassCastException。

知道以下的語法,哪些可以通過編譯,哪些可以扮演成功作什麼?來考慮一個需

求,寫個 static的 swim()方法,讓會游的東西都游起來,在不會使用介面多型語

法時,也許你會寫下:

public static void doSwim(Fish fish) {

fish.swim();

}

public static void doSwim(Human human) {

human.swim();

}

public static void doSwim(Submarine submarine) {

Page 8: Java SE 7 技術手冊第七章草稿 - 何謂介面?

Java SE 7技術手冊草稿

submarine.swim();

}

老實說,如果已經會寫下接收 Fish的 doSwim()版本,程式還算是不錯的,因

為至少你知道,只要有繼承 Fish,無論是 Anemonefish、Shark或 Piranha,都

可以使用 Fish 的 doSwim()版本,至少你會使用繼承時的多型,至於 Human 與

Submarine各使用其接收 Human及 Submarine的 doSwim()版本。

問題是,如果「種類」很多怎麼辦?多了水母、海蛇、蟲等種類呢?每個種類重

載一個方法出來嗎?其實在你的設計中,會游泳的東西,都擁有 Swimmer的行為,

都實作了 Swimmer介面,所以你只要這麼設計就可以了:

OceanWorld2 Ocean.java

package cc.openhome;

public class Ocean {

public static void doSwim(Swimmer swimmer) {

swimmer.swim();

}

public static void main(String[] args) {

doSwim(new Anemonefish("尼莫"));

doSwim(new Shark("蘭尼"));

doSwim(new Human("賈斯汀"));

doSwim(new Submarine("黃色一號"));

}

}

執行結果如下: 小丑魚 尼莫 游泳 鯊魚 蘭尼 游泳 人類 賈斯汀 游泳 潛水艇 黃色一號 潛行

只要是實作 Swimmer 介面的物件,都可以使用範例中的 doSwim()方法,

Anemonefish、Shark、Human、Submarine等,都實作了 Swimmer介面,再多

種類,只要物件擁有 Swimmer行為,你就都不用撰寫新的方法,可維護性顯然提高

許多!

7.1.3 解決解決解決解決需求需求需求需求變化變化變化變化

相信你一定常聽人家說,寫程式要有彈性,要有可維護性!那麼什麼叫有彈性?

何謂可維護?老實說,這是有點抽象的問題,這邊從最簡單的定義開始:如果增加新

參數是參數是參數是參數是 Swimmer型態型態型態型態

Lab

Page 9: Java SE 7 技術手冊第七章草稿 - 何謂介面?

Java SE 7技術手冊草稿

的需求,原有的程式無需修改,只需針對新需求撰寫程式,那就是有彈性、具可維護

性的程式。

以 7.1.1提到的需求為例,如果今天老闆突發奇想,想把海洋樂園變為海空

樂園,有的東西會游泳,有的東西會飛,有的東西會游也會飛,那麼現有的程式可以

應付這個需求嗎?

仔細想想,有的東西會飛,但不限於某種東西才有「飛」這個行為,有了先前的

經驗,你使用 interface定義了 Flyer介面:

OceanWorld3 Flyer.java

package cc.openhome;

public interface Flyer {

public abstract void fly();

}

Flyer介面定義了 fly()方法,程式中想要飛的東西,可以實作 Flyer介面,

假設有台海上飛機具有飛行的行為,也可以在海面上航行,可以定義 Seaplane 實

作、Swimmer與 Flyer介面:

OceanWorld3 Airplane.java

package cc.openhome;

public class Seaplane implements Swimmer, Flyer {

private String name;

public Seaplane(String name) {

this.name = name;

}

@Override

public void fly() {

System.out.printf("海上飛機 %s 在飛%n", name);

}

@Override

public void swim() {

System.out.printf("海上飛機 %s 航行海面%n", name);

}

}

在 Java 中,類別可以實作兩個以上的類別類別可以實作兩個以上的類別類別可以實作兩個以上的類別類別可以實作兩個以上的類別,,,,也就是擁有兩種以上的行為也就是擁有兩種以上的行為也就是擁有兩種以上的行為也就是擁有兩種以上的行為。例如

Seaplane就同時擁有 Swimmer與 Flyer的行為。

Lab

Lab

Page 10: Java SE 7 技術手冊第七章草稿 - 何謂介面?

Java SE 7技術手冊草稿

如果是會游也會飛的飛魚呢?飛魚是一種魚,可以繼承 Fish類別,飛魚會飛,

可以實作 Flyer介面:

OceanWorld3 FlyingFish.java

package cc.openhome;

public class FlyingFish extends Fish implements Flyer {

public FlyingFish(String name) {

super(name);

}

@Override

public void swim() {

System.out.println("飛魚游泳");

}

@Override

public void fly() {

System.out.println("飛魚會飛");

}

}

正如範例所示,在在在在 Java中中中中,,,,類別可以同時繼承某個類別類別可以同時繼承某個類別類別可以同時繼承某個類別類別可以同時繼承某個類別,,,,並實作某些介面並實作某些介面並實作某些介面並實作某些介面。例

如 FlyingFish是一種魚,也擁有 Flyer的行為。如果現在要讓所有會游的東西游

泳,那麼 7.1.1 節中的 doSwim()方法就可以滿足需求了,因為 Seaplane 擁有

Swimmer的行為,而 FlyingFish也擁有 Swimmer的行為:

OceanWorld3 Ocean.java

package cc.openhome;

public class Ocean {

public static void doSwim(Swimmer swimmer) {

swimmer.swim();

}

public static void main(String[] args) {

略...

doSwim(new Seaplane("空軍零號空軍零號空軍零號空軍零號"));

doSwim(new FlyingFish("甚平甚平甚平甚平"));

}

}

Lab

Lab

Page 11: Java SE 7 技術手冊第七章草稿 - 何謂介面?

Java SE 7技術手冊草稿

就滿足目前需求來說,你所作的就是新增程式碼來滿足需求,但沒有修改舊有既

存的程式碼,你的程式確實擁有某種程度的彈性與可維護性。

圖圖圖圖 7.5 海空樂園目前海空樂園目前海空樂園目前海空樂園目前設計設計設計設計架構架構架構架構

當然需求是無止盡的,原有程式架也許確實可滿足某些需求,但有些需求也可能

超過了原有架構預留之彈性,一開始要如何設計才會有彈性,是必須靠經驗與分析判

斷,不用為了保有程式彈性的彈性而過度設計,因為過大的彈性表示過度預測需求,

有的設計也許從不會遇上事先假設的需求。

例如,也許你預先假設會遇上某些需求而設計了一個介面,但從程式開發至生命

週期結束,該介面從未被實作過,或者有一個類別實作過該介面,那麼該介面也許就

不必存在,你事先的假設也許就是過度預測需求。

事先的設計也有可能因為需求不斷增加,而超出原本預留之彈性。例如老闆又開

口了:不是所有的人都會游泳啊!有的飛機只會飛,不能停在海上啊!

好吧!並非所有的人都會游泳,所以不再讓 Human實作 Swimmer:

OceanWorld4 Human.java

package cc.openhome;

public class Human {

protected String name;

public Human(String name) {

this.name = name;

}

public String getName() {

return name;

}

}

假設只有游泳選手會游泳,游泳選手是一種人,並擁有 Swimmer的行為:

OceanWorld4 Human.java

Lab

Lab

Page 12: Java SE 7 技術手冊第七章草稿 - 何謂介面?

Java SE 7技術手冊草稿

package cc.openhome;

public class SwimPlayer extends Human implements Swimmer {

public SwimPlayer(String name) {

super(name);

}

@Override

public void swim() {

System.out.printf("游泳選手 %s 游泳%n", name);

}

}

有的飛機只會飛,所以設計一個 Airplane 類別作為 Seaplane 的父類別,

Airplane實作 Flyer介面:

OceanWorld4 Airplane.java

package cc.openhome;

public class Airplane implements Flyer {

protected String name;

public Airplane(String name) {

this.name = name;

}

@Override

public void fly() {

System.out.printf("飛機 %s 在飛%n", name);

}

}

Seaplane會在海上航行,所以在繼承 Airplane之後,必須實作 Swimmer介

面:

OceanWorld4 Seaplane.java

package cc.openhome;

public class Seaplane extends Airplane implements Swimmer {

public Seaplane(String name) {

super(name);

}

Lab

Lab

Page 13: Java SE 7 技術手冊第七章草稿 - 何謂介面?

Java SE 7技術手冊草稿

@Override

public void fly() {

System.out.print("海上");

super.fly();

}

@Override

public void swim() {

System.out.printf("海上飛機 %s 航行海面%n", name);

}

}

不過程式中的直昇機就只會飛:

OceanWorld4 Seaplane.java

package cc.openhome;

public class Helicopter extends Airplane {

public Helicopter(String name) {

super(name);

}

@Override

public void fly() {

System.out.printf("飛機 %s 在飛%n", name);

}

}

這一連串的修改,都是為了調整程式架構,這只是個簡單的示範,想像一下,在

更大規模的程式中調整程架構會有多麼麻煩,而且不只是修改程式很麻煩,沒有被修

改到的地方,也有可能因此出錯:

Lab

Page 14: Java SE 7 技術手冊第七章草稿 - 何謂介面?

Java SE 7技術手冊草稿

圖圖圖圖 7.6 沒有動到這邊啊沒有動到這邊啊沒有動到這邊啊沒有動到這邊啊!!!!怎麼出錯了怎麼出錯了怎麼出錯了怎麼出錯了????

程式架構很重要!這邊就是個例子,因為 Human不在實作 Swimmer介面了,因

此不能再套用 doSwim()方法!應該改用 SwimPlayer了!

不好的架構下要修改程式,很容易牽一髮而動全身,想像一下在更複雜的程式

中,修改程式之後,到處出錯的窘境,也有不少人維護到架構不好的程式,抓狂到想

砍掉重練的情況。

提示提示提示提示 對於一些人來說,軟體看不到,摸不著,改程式似乎也不需成本,也因

此架構這東西經常被漠視。曾經聽過一個比喻是這樣的:沒人敢在蓋十

幾層高樓之後,要求修改地下室架構,但軟體業界常常在作這種事。

也許老闆又想到了:水裡的話,將淺海游泳與深海潛行分開好了!就算心裡再千

百個不願意,你還是摸摸鼻子改了:

OceanWorld4 Diver.java

package cc.openhome;

public interface Diver extends Swimmer {

public abstract void dive();

}

在 Java 中,介面可以繼承自另一個介面介面可以繼承自另一個介面介面可以繼承自另一個介面介面可以繼承自另一個介面,,,,也就是繼承父介面行為也就是繼承父介面行為也就是繼承父介面行為也就是繼承父介面行為,,,,再於子介面再於子介面再於子介面再於子介面

中額外定義行為中額外定義行為中額外定義行為中額外定義行為。假設一般的船可以在淺海航行:

OceanWorld4 Boat.java

package cc.openhome;

public class Boat implements Swimmer {

protected String name;

public Boat(String name) {

this.name = name;

}

@Override

public void swim() {

System.out.printf("船在水面 %s 航行%n", name);

}

}

潛水航是一種船,可以在淺海游泳,也可以在深海潛行:

OceanWorld4 Submarine.java

package cc.openhome;

Lab

Lab

Lab

Page 15: Java SE 7 技術手冊第七章草稿 - 何謂介面?

Java SE 7技術手冊草稿

public class Submarine extends Boat implements Diver {

public Submarine(String name) {

super(name);

}

@Override

public void dive() {

System.out.printf("潛水艇 %s 潛行%n", name);

}

}

需求不斷變化,架構也有可能因此而修改,好的架構在修改時,其實也不會全部

的程式碼都被牽動,這就是設計的重要性,不過像這位老闆無止境地在擴張需求,他

說一個你改一個,也不是辦法,找個時間,好好跟老闆談談這個程式的需求邊界到底

是什麼吧!

圖圖圖圖 7.7 你的程式有彈性嗎你的程式有彈性嗎你的程式有彈性嗎你的程式有彈性嗎????

7.2 介面語法細節介面語法細節介面語法細節介面語法細節 上一節介紹了介面的基礎觀念與語法,然而結合 Java 的特性,介面還有一些細

節必須明瞭,像是介面中的預設語法、介面中定義常數之運用、匿名內部類別之撰寫

等,這都將於本節中詳細說明。