我們拿人和程序員舉個(gè)例子。人是一個(gè)大類(lèi),程序員是繼承自人的子類(lèi)??纯催@句話(huà):人需要吃飯。這句話(huà)我們把“人”換成“程序員”,就是:程序員需要吃飯,這樣換不會(huì)有什么問(wèn)題?,F(xiàn)在我們反過(guò)來(lái),把“程序員可以用計(jì)算機(jī)寫(xiě)程序”里邊的程序員換成“人”,就是:人可以用計(jì)算機(jī)寫(xiě)程序。這樣就不一定正確了,否則問(wèn)題可就大了,我們這些程序員只怕沒(méi)得飯吃了。
這個(gè)就是里氏代換原則:使用父類(lèi)的地方肯定可以用它的一個(gè)子類(lèi)來(lái)替換掉,但是使用一個(gè)子類(lèi)的時(shí)候用它的父類(lèi)來(lái)替換就不一定正確了。
好,現(xiàn)在我們回到程序設(shè)計(jì)里邊來(lái)。
看看下面的程序:
一個(gè)學(xué)校里邊,有兩種人:學(xué)生、老師。他們都要吃飯和睡覺(jué)。
public interface 人{(lán)
??? void 吃飯();
??? void 睡覺(jué)();
}
?
public class 學(xué)生 implements 人{(lán)
??? public void 吃飯(){
??????? //去食堂吃飯
??? }
??? public void 睡覺(jué)(){
??????? //回寢室睡覺(jué)
??? }
??? ...//其他特有方法,比如泡妞、打游戲
}
??? public void 吃飯(){
??????? //去食堂吃飯
??? }
??? public void 睡覺(jué)(){
??????? //回寢室睡覺(jué)
??? }
??? ...//其他特有方法,比如泡妞、打游戲
}
?
public class 老師 implements 人{(lán)
??? public void 吃飯(){
??????? //回家吃飯
??? }
??? public void 睡覺(jué)(){
??????? //回家睡覺(jué)
??? }
??? ...//其它特有方法,比如為生兒育女傳宗接代的歷史使命努力等不足為外人道的事情
}
??? public void 吃飯(){
??????? //回家吃飯
??? }
??? public void 睡覺(jué)(){
??????? //回家睡覺(jué)
??? }
??? ...//其它特有方法,比如為生兒育女傳宗接代的歷史使命努力等不足為外人道的事情
}
?
public class 學(xué)校{
??? public void 開(kāi)飯(人 ren){
??????? ren.吃飯();
??? }
??? public void 開(kāi)飯(人 ren){
??????? ren.吃飯();
??? }
??? public void 放學(xué)(人 ren){
??????? ren.睡覺(jué)();
??? }
}
??????? ren.睡覺(jué)();
??? }
}
?
這里就用到了里氏代換原則,"開(kāi)飯()"和"放學(xué)()"的參數(shù)都是人,那么這個(gè)地方如果換成學(xué)生和老師肯定也可以。
?
人 a = new 學(xué)生();
學(xué)校.開(kāi)飯(a);
學(xué)校.放學(xué)(a);
學(xué)校.開(kāi)飯(a);
學(xué)校.放學(xué)(a);
?
這樣執(zhí)行的結(jié)果就是學(xué)生回寢室吃飯。
?
人 b = new 老師();
學(xué)校.開(kāi)飯(b);
學(xué)校.放學(xué)(b);
學(xué)校.開(kāi)飯(b);
學(xué)校.放學(xué)(b);
?
這樣執(zhí)行的結(jié)果就是老師回家吃飯。
?
為什么要這樣寫(xiě)呢?這樣寫(xiě)有什么好處呢?
我在開(kāi)飯的時(shí)候完全可以直接調(diào)用"學(xué)生.吃飯();"、"老師.吃飯();"啊。
接著看。
有一天,學(xué)校里來(lái)了第三種人,家長(zhǎng)。
家長(zhǎng)既不是去寢室睡覺(jué)也不是回家睡覺(jué),而是旅館睡覺(jué),既不是去食堂吃飯也不是回家吃飯,而是去下館子。
這個(gè)時(shí)候?qū)W校這個(gè)系統(tǒng)該怎么處理呢?
如果原來(lái)沒(méi)有定義"人"這個(gè)接口那就麻煩啦,所有用到人的地方代碼都要改。
現(xiàn)在不一樣了,我可以直接定義一個(gè)類(lèi):家長(zhǎng),這個(gè)類(lèi)實(shí)現(xiàn)人這個(gè)接口就可以了。
好,看代碼:
我在開(kāi)飯的時(shí)候完全可以直接調(diào)用"學(xué)生.吃飯();"、"老師.吃飯();"啊。
接著看。
有一天,學(xué)校里來(lái)了第三種人,家長(zhǎng)。
家長(zhǎng)既不是去寢室睡覺(jué)也不是回家睡覺(jué),而是旅館睡覺(jué),既不是去食堂吃飯也不是回家吃飯,而是去下館子。
這個(gè)時(shí)候?qū)W校這個(gè)系統(tǒng)該怎么處理呢?
如果原來(lái)沒(méi)有定義"人"這個(gè)接口那就麻煩啦,所有用到人的地方代碼都要改。
現(xiàn)在不一樣了,我可以直接定義一個(gè)類(lèi):家長(zhǎng),這個(gè)類(lèi)實(shí)現(xiàn)人這個(gè)接口就可以了。
好,看代碼:
?
public class 家長(zhǎng) implements 人{(lán)
??? public void 吃飯(){
??????? //下館子
??? }
??? public void 睡覺(jué)(){
??????? //去旅館睡覺(jué)
??? }
??? ...//其它特有方法,比如會(huì)見(jiàn)老師,曉之以錢(qián),動(dòng)之以利等等,不一而足
}
??? public void 吃飯(){
??????? //下館子
??? }
??? public void 睡覺(jué)(){
??????? //去旅館睡覺(jué)
??? }
??? ...//其它特有方法,比如會(huì)見(jiàn)老師,曉之以錢(qián),動(dòng)之以利等等,不一而足
}
?
在調(diào)用的時(shí)候不需要修改任何代碼,還和原來(lái)一樣:
?
人 c=new 家長(zhǎng)();
學(xué)校.開(kāi)飯(c);
學(xué)校.放學(xué)(c);
學(xué)校.開(kāi)飯(c);
學(xué)校.放學(xué)(c);
?
輕松搞定家長(zhǎng)的食宿問(wèn)題!
?
這樣一來(lái)學(xué)校來(lái)再多的客人都沒(méi)關(guān)系啊,絕對(duì)可以應(yīng)付自如,這也就是傳說(shuō)中的可擴(kuò)展性!
不知道初學(xué)者看到這里是不是能夠明白接口的作用。如果你還不明白,那么你把人這個(gè)接口去掉,自己寫(xiě)一個(gè)學(xué)校開(kāi)飯和放學(xué)的類(lèi),然后再加一個(gè)家長(zhǎng)這個(gè)新新人類(lèi)進(jìn)去,看看你的代碼是什么樣子的,再想一下在人口這么多的中國(guó),萬(wàn)一哪天你的學(xué)校里來(lái)了成千上萬(wàn)個(gè)新新人類(lèi)你該怎么辦!