面向對象七大基本原則
案例需求: 一個人想買一個電腦。
簡單實現:
class User { getComputer () { console.log(‘跑很遠去買220v電源‘),//表達的是這個過程很復雜, console.log(‘跑很遠買16存顯示器‘) //。。。。。 console.log(‘組裝‘); } }; new User().getComputer();
上面的實現滿足了我的需求。但是有個問題:在getComputer方法中,每次都要跑很遠去買,然後自己組裝,整個過程繁瑣復雜(腦補getComputer方法內部的代碼很長很長)。如果能有人送貨,就好了。
解決思路就是單一原則: 一個類或方法只做一件事。
class User { dianyuan(num) { console.log(`買了個${num}v電源`) } screen(num) { console.log(`買了個${num}寸顯示器`) } zz() { console.log(‘組裝‘) } getComputer () { this.dianyuan(220); this.screen(20); //。。。。。 this.zz(); } }; new User().getComputer();
在新實現中,我隨便打幾個電話(將不同類型的零件單獨定義為各自的函數,調用dianyuan/screen...,實現單一原則),就能得到想要類型的零件。但是,不是每個人都像我這樣了解電腦零件及組裝過程的,對於小白來說,它希望有個經銷商能直接幫他完成零件購買及組裝的過程,
解決思路:再次使用單一原則
class Computer { dianyuan() { console.log(`買了個200v電源`) } screen(num) { console.log(`買了個17寸顯示器`) } all() { this.dianyuan(); this.screen(); } } class User { zz() { console.log(‘組裝‘) } getComputer () { let computer = new Computer(220, 20); computer.all(); this.zz(); } }; new User().getComputer();
這次實現中, 我將獲取零件的過程封裝成了一個類,它能返回組裝一個電腦所需要的所有零件;從此小白獲取一個電腦的方法就是調用以下Computer.all()方法。但是只有一個經銷商實在是太被動了,我不能貨比三家,我希望所有的經銷商都具備獲取所有零件的能力,但是各自零件的類型及價錢又能讓我可以選擇。
解決思路:
1抽象:抽取事物的本質,剔除具體表現。
2裏氏替換:子類能夠出現在所有父類出現的地方。
3依賴倒置:程序應該依賴抽象接口, 而不依賴具體實現。
class SuperComputer { dianyuan() { } screen() { } all() { this.dianyuan(); this.screen(); } } class SubOneComputer extends SuperComputer{ dianyuan() { console.log(‘我們家的220電源10元‘) } screen() { console.log(‘我們家17屏幕20元‘); } } class SubTwoComputer extends SuperComputer { dianyuan() { console.log(‘我們家的220電源20元‘) } screen() { console.log(‘我們家17屏幕10元‘); } } class User { zz() { console.log(‘組裝‘) } getComputer (computer) { //為了程序的健壯性, 你需要判斷這個參數是否是某經銷商的實例(能夠調用all()),從而產生某個經銷商的依賴, 然後最好的實現方式就是判斷它是否是某個抽象類的實例,避免對擴展子類的依賴, 這就是依賴倒置原則 if (computer instanceof SuperComputer) { computer.all(); this.zz(); } else { console.log(‘請傳入經銷商的實例‘) } } }; let xiaoming= new User(); xiaoming.getComputer(new SubOneComputer()); let xiaohong = new User() xioahong.getComputer(new SubTwoComputer());
小紅/小明通過不同經銷商那拿到不同類型的零件,但是零件肯定是齊全的,這得力於兩點。
1:抽象類SuperComputer為所有的經銷商定義了標準(是不是有點抽象接口的概念)。
2:經銷商實現了SuperComputer定義的所有零件方法。這就是裏氏替換帶來的好處。
3:為了User.getComputer()的健壯性, 你需要判斷computer是否是某經銷商的實例(能夠調用all()),從而產生某個經銷商的依賴, 然後最好的實現方式就是判斷它是否是某個抽象類的實例,從而避免對擴展子類的依賴,畢竟抽象類的最可靠。
然後 而不然後經銷商又了新的問題, 為了盈利,他必須擴大業務範圍。
解決思路:
開閉原則:對修改關閉, 對擴展開放
class SuperComputer { dianyuan() { } screen() { } all() { this.dianyuan(); this.screen(); } } class SubOneComputer extends SuperComputer{ dianyuan() { console.log(‘我們家的220電源10元‘) } screen() { console.log(‘我們家17屏幕20元‘); } paper() { console.log(‘A4紙1毛一張‘) } } class SubTwoComputer extends SuperComputer { dianyuan() { console.log(‘我們家的220電源20元‘) } screen() { console.log(‘我們家17屏幕10元‘); } netline() { console.log(‘網線1米2元‘) } } class User { zz() { console.log(‘組裝‘) } getComputer (computer) { //為了程序的健壯性, 你需要判斷這個參數是否是某經銷商的實例(能夠調用all()),從而產生某個經銷商的依賴, 然後最好的實現方式就是判斷它是否是某個抽象類的實例,避免對擴展子類的依賴, 這就是依賴倒置原則 if (computer instanceof SuperComputer) { computer.all(); this.zz(); } else { console.log(‘請傳入經銷商的實例‘) } } }; let xiaoming= new User(); xiaoming.getComputer(new SubOneComputer()); let xiaohong = new User() xioahong.getComputer(new SubTwoComputer());
上面的兩個經銷商為了利潤, 各自擴大了經營範圍(paper(), netline()),他們是對SupterComputer的擴展,而不能為單獨的經銷商在SuperComputer類中去添加跟電腦零件無關的方法,保證抽象的單一性,穩定性。
還有一個問題, 現在所有的小白能輕松的從不同的經銷商那裏獲取全部零件,但是還是要自己組裝, 還不夠方便,其實小白們只需要找到一個會組裝的人,這個組裝的人肯定對於電腦零件是非常熟悉的,小白們不在關心電腦零件問題,。
解決思路:
迪米特法則:一個對象應該對其他對象保持最少的了解
class SuperComputer { dianyuan() { } screen() { } all() { this.dianyuan(); this.screen(); } } class SubOneComputer extends SuperComputer{ dianyuan() { console.log(‘我們家的220電源10元‘) } screen() { console.log(‘我們家17屏幕20元‘); } paper() { console.log(‘A4紙1毛一張‘) } } class SubTwoComputer extends SuperComputer { dianyuan() { console.log(‘我們家的220電源20元‘) } screen() { console.log(‘我們家17屏幕10元‘); } netline() { console.log(‘網線1米2元‘) } } //組裝類 class InitComputer { software() { console.log(‘安裝軟件‘) } hardware(computer) { if (computer instanceof SuperComputer) { computer.all(); } else { console.log(‘請傳入經銷商的實例‘) } } zz(money) { switch(money) { case 5000: this.hardware(new SubOneComputer());//5000元的配置 case 4000: this.hardware(new SubTwoComputer());//4000元的配置 } this.software(); console.log(‘組裝完畢‘); } } class User { getComputer (money) { new InitComputer().zz(money); } }; let xiaoming= new User(); xiaoming.getComputer(4000); let xiaohong = new User() xioahong.getComputer(5000);
終於搞定了,現在小白只需要給組裝類money就能得到一臺相應配置的電腦, 不用在找經銷商及自己組裝了。這就是迪米特法則, 小白不需要熟悉經銷商的套路,而是通過組裝類這個中間人去搞定。
以上的例子是我對公司培訓面向對象6大基本原則的理解,總結以下:單一原則,開閉原則,裏氏替換,抽象接口,依賴倒置,迪米特法則
面向對象七大基本原則