1. 抽象類(lèi)和抽象方法
- 抽象方法
這種方法時(shí)不完整的续镇,只有聲明沒(méi)有方法體:
abstract void f();
- 抽象類(lèi)
包含抽象方法的類(lèi)是抽象類(lèi)秆乳,包含抽象方法的類(lèi)必須要聲明為抽象類(lèi)啥箭。
如果從一個(gè)類(lèi)繼承,并創(chuàng)建該新類(lèi)的對(duì)象,就必須為基類(lèi)中的所有抽象方法提供方法定義,如果不這樣做眠蚂,導(dǎo)出類(lèi)也是抽象類(lèi),且編譯器會(huì)強(qiáng)制用abstract關(guān)鍵字來(lái)限定這個(gè)類(lèi)斗躏。
創(chuàng)建抽象類(lèi)和抽象方法很有用逝慧,因?yàn)樗鼈兛梢允诡?lèi)的抽象性明確起來(lái),并告訴用戶(hù)和編譯器打算怎樣來(lái)使用它們。抽象類(lèi)還是很有用的重構(gòu)工具馋艺,它們可以使人們很容易的將公共方法沿著繼承層次結(jié)構(gòu)向上移動(dòng)栅干。
2. 接口
- interface關(guān)鍵字使抽象的概念更向前邁了一步。
- abstract允許在類(lèi)中創(chuàng)建一個(gè)或多個(gè)沒(méi)有任何定義的方法捐祠,提供了接口部分,但沒(méi)提供實(shí)現(xiàn)桑李,實(shí)現(xiàn)由此類(lèi)的繼承者創(chuàng)建踱蛀,但也有已經(jīng)實(shí)現(xiàn)的方法。interface產(chǎn)生了一個(gè)完全抽象的類(lèi)贵白,沒(méi)有提供任何具體實(shí)現(xiàn)率拒。
- 一個(gè)接口表示“** 所有實(shí)現(xiàn)了該特定接口的類(lèi)看起來(lái)都是這樣 **”。接口被用來(lái)建立類(lèi)與類(lèi)之間的協(xié)議禁荒。
- 接口不僅僅是一個(gè)極度抽象的類(lèi)猬膨,因?yàn)樗试S人們創(chuàng)建一個(gè)能被向上轉(zhuǎn)型為多種基類(lèi)的類(lèi)型,來(lái)實(shí)現(xiàn)某種類(lèi)似繼承多個(gè)基類(lèi)的特性呛伴。
- 接口中的方法都是public的勃痴。
3. 完全解耦
類(lèi)Class1和Class2有相同的接口元素,Class1能用于A.process()热康,由于Class2不是繼承于Class1沛申,Class2并不知道要將它當(dāng)做Class1來(lái)用,所以Class2不能用于A.process()姐军。而如果Class1是個(gè)接口的話(huà)铁材,限制就會(huì)松動(dòng)。
將接口從具體實(shí)現(xiàn)中解耦可以使接口應(yīng)用于多種不同的具體實(shí)現(xiàn)奕锌,所以代碼就更具有復(fù)用性著觉。
4. Java中的多重繼承
接口沒(méi)有任何具體實(shí)現(xiàn),所以沒(méi)有任何與接口相關(guān)的存儲(chǔ)惊暴,那么就無(wú)法阻止多個(gè)接口的結(jié)合饼丘。 可以表示“一個(gè)x可以是一個(gè)a,一個(gè)b缴守,也可以是一個(gè)c”葬毫。
使用接口的核心原因是:為了能夠向上轉(zhuǎn)型為多個(gè)基類(lèi);
另一個(gè)原因與使用抽象基類(lèi)相同:防止客戶(hù)端程序員創(chuàng)建該類(lèi)的對(duì)象屡穗,并確保這只是創(chuàng)建一個(gè)接口贴捡。
5. 接口與工廠
工廠方法設(shè)計(jì)模式:與直接調(diào)用構(gòu)造器不同,在工廠對(duì)象上調(diào)用的是創(chuàng)建方法村砂,該工廠對(duì)象將生成接口的某個(gè)實(shí)現(xiàn)的對(duì)象烂斋。這種方式將代碼與接口的實(shí)現(xiàn)分離。如下:
package com.zhangyue.learn;
interface Game1{
boolean move();
}
interface GameFactory{
Game1 getGame();
}
class Checkers implements Game1{
private int moves = 0;
private static final int MOVES = 3;
public boolean move(){
System.out.println("Checkers move " + moves);
return ++moves != MOVES;
}
}
class CheckersFactorty implements GameFactory{
public Game1 getGame(){
return new Checkers();
}
}
class Chess1 implements Game1{
private int moves = 0;
private static final int MOVES = 4;
public boolean move(){
System.out.println("Chess move " + moves);
return ++moves != MOVES;
}
}
class ChessFactory implements GameFactory{
public Game1 getGame(){
return new Chess1();
}
}
public class Games {
public static void playGame(GameFactory factorty){
Game1 s = factorty.getGame();
while(s.move());
}
public static void main(String[] args) {
playGame(new CheckersFactorty());
playGame(new ChessFactory());
}
}
/*output
Checkers move 0
Checkers move 1
Checkers move 2
Chess move 0
Chess move 1
Chess move 2
Chess move 3
*/
如果不是工廠方法,就必須在代碼某處指定將要?jiǎng)?chuàng)建的Game的確切類(lèi)型汛骂,以便調(diào)用合適的構(gòu)造器罕模。
這樣做常見(jiàn)的原因是構(gòu)建框架:假如一個(gè)游戲系統(tǒng),在相同的棋盤(pán)上下Checker和Chess帘瞭。
接口是重要的工具但是容易被濫用淑掌,恰當(dāng)?shù)脑瓌t是優(yōu)先選擇類(lèi),如果接口的必須性非常明確再重構(gòu)蝶念。