上一節(jié)中我們介紹了,依賴倒置,依賴倒置利用抽象的穩(wěn)定性來架構(gòu)我們的系統(tǒng),是我們經(jīng)常能遇到的一種原則,比如說面向接口編程。
這一節(jié)中,我們來說說里氏替換原則,這個(gè)原則其實(shí)非常非常的簡單,其實(shí)與依賴倒置相結(jié)合來看,就是希望我們用抽象的方法來構(gòu)建項(xiàng)目而非具體的實(shí)現(xiàn),里氏替換原則就是推薦我們不要重寫父類中具體的實(shí)現(xiàn)來構(gòu)建我們的項(xiàng)目。
我們來深入研究研究。
那么翻譯成比較容易理解的話,就是說,子類一般不該重寫父類的方法,因?yàn)楦割惖姆椒ㄒ话愣际菍ν夤嫉慕涌冢蔷哂胁豢勺冃缘?,你不該將一些不該變化的東西給修改掉。
上述只是通常意義上的說法,很多情況下,我們其實(shí)不必要太過于在意這個(gè)原則,因?yàn)橄鄬τ诶^承帶給我們的好處,很多時(shí)候我們會忽略掉其帶來的弊端。比如缺省適配器,裝飾器模式等一些設(shè)計(jì)模式
不過就算如此,如果你真的遇見了不得不重寫父類方法的場景,那么請你考慮,你是否真的要把這個(gè)類作為子類出現(xiàn)在這里,或者說這樣做所換來的是否能彌補(bǔ)你失去的東西,比如子類無法代替父類工作,那么就意味著如果你的父類可以在某一個(gè)場景里工作的很正常,那么你的子類當(dāng)然也應(yīng)該可以,否則就會出現(xiàn)下述場景。
//某一個(gè)類public class SomeoneClass { //有某一個(gè)方法,使用了一個(gè)父類類型 public void someoneMethod(Parent parent){ parent.method(); }}
父類代碼如下
public class Parent { public void method(){ System.out.println("parent method"); }}
結(jié)果我有一個(gè)子類把父類的方法給覆蓋了,并且拋出了一個(gè)異常。
public class SubClass extends Parent{ //結(jié)果某一個(gè)子類重寫了父類的方法,說不支持該操作了 public void method() { throw new UnsupportedOperationException(); } }
這個(gè)異常是運(yùn)行時(shí)才會產(chǎn)生的,也就是說,我的SomeoneClass并不知道會出現(xiàn)這種情況,結(jié)果就是我調(diào)用下面這段代碼的時(shí)候,本來我們的思維是Parent都可以傳給someoneMethod完成我的功能,我的SubClass繼承了Parent,當(dāng)然也可以了,但是最終這個(gè)調(diào)用會拋出異常。
public class Client { public static void main(String[] args) { SomeoneClass someoneClass = new SomeoneClass(); someoneClass.someoneMethod(new Parent()); someoneClass.someoneMethod(new SubClass()); }}
這就相當(dāng)于埋下了一個(gè)個(gè)陷阱,因?yàn)楸緛砦覀兊脑瓌t是,父類可以完成的地方,我用子類替代是絕對沒有問題的,但是這下反了,我每次使用一個(gè)子類替換一個(gè)父類的時(shí)候,我還要擔(dān)心這個(gè)子類有沒有給我埋下一個(gè)上面這種炸彈。
所以里氏替換原則是一個(gè)需要我們深刻理解的原則,因?yàn)橥袝r(shí)候違反它我們可以得到很多,失去一小部分,但是有時(shí)候卻會相反,所以要想做到活學(xué)活用,就要深刻理解這個(gè)原則的意義所在。
到這里我們已經(jīng)掌握了四個(gè)原則(單一職責(zé)原則,接口隔離原則,依賴倒置原則,里氏替換原則)
下一個(gè)原則是非常非常重要的原則。甚至說,我們前面講的都是為了下一個(gè)開閉原則做的準(zhǔn)備也不為過。所以說掌握這四種原則是非常非常重要的。