軟件實體(類、模塊、函數)等應該對擴展是開放的,對修改是封閉的。javascript
對擴展開放:有新的需求或變化時,能夠對現有代碼進行擴展,以適應新的狀況。java
對修改封閉:類一旦設計完成,能夠獨立完成其工做,而不要對類進行修改。設計模式
項目需求變遷過程當中,常常會找到相關代碼而後改寫。擴展一個模塊最經常使用的方式固然是修改它的源碼,然而改動代碼是一種危險的行爲,剛剛改好一個bug頗有可能不知不覺中引起了其餘的bug。函數
那麼既可使用開放封閉原則的思想:當須要改變一個程序的功能或者給這個程序增長新的功能的時候,可使用增長代碼的方式,可是不容許改動程序的源代碼。spa
封裝變化,只將常常變化的部分進行抽象prototype
舉例說明:設計
①利用對象的多態性消除條件分支代理
var makeSound = function(animal) { if (animal instanceof Duck) { console.log('gagaga'); } else if (animal instanceof Chicken) { console.log('gegege'); } } var Duck = function () {} var Chicken = function () {} makeSound(new Duck()); makeSound(new Chicken()); //多了一隻狗,函數變成 var makeSound = function(animal) { if (animal instanceof Duck) { console.log('gagaga'); } else if (animal instanceof Chicken) { console.log('gegege'); } else if (animal instanceof Dog) { console.log('wangwang'); } } var Dog = function () {} makeSound(new Dog());
利用多態把不變的部分隔離出來,把可變的部分封裝起來code
var makeSound = function (animal) { animal.sound(); } var Duck = function () {} Duck.prototype.sound = function() { console.log('gagaga'); } var Chicken = function () {} Chicken.prototype.sound = function() { console.log('gegege'); } makeSound(new Duck()); makeSound(new Chicken()); //多加動物狗卻不用改變原有的makesound函數 var Dog = function () {} Dog.prototype.sound = function () { console.log('wangwang'); } makeSound(new Dog());
②放置掛鉤(hook)對象
是分離變化的一種方式。在程序有可能發生變化的地方放置一個掛鉤,掛鉤的返回結果決定了程序下一步的走向。
③使用回調函數
回調函數是一種特殊的掛鉤。能夠把易於變化的邏輯封裝在回調函數裏,而後把回調函數當作參數傳入一個穩定的和封閉的函數中。
好的設計都是經得起開放封閉-原則的考驗。開放-封閉原則是編寫一個好程序的目標,其餘設計原則都是達到這個目標的過程。
①發佈-訂閱模式
待續
②模板方法模式
待續
③策略模式
待續
④代理模式
待續
⑤職責鏈模式
待續
總會存在一些沒法封閉的變化。。。
挑選出最容易發生變化的地方,而後構造抽象來封閉這些變化。
在不可避免發生修改的時候,儘可能修改那些相對容易修改的地方。拿一個開源庫來講,修改它提供的配置文件,總比修改它的源代碼來的簡單。
程序一開始就儘可能遵循開放-封閉原則並非一件容易的事。一方面很難未卜先知程序的變化在哪裏,另外一方面需求排期時間有限,能夠說服本身去接受不合理代碼的第一次愚弄。最初編寫代碼時候,假設變化永遠不會發生,有利於迅速完成需求。當變化發生而且對接下來的工做形成影響的時候,再回過來封裝這些變化的地方。確保不掉進同一個坑裏。
參考:
《JavaScript設計模式與開發實踐》 曾探著 AlloyTeam出品