一、程式、演算法
本質
程式=演算法+數結結構
演算法=邏輯+控制
程式=演算法+數結結構,這個是眾所周知了,演算法這個解釋則比較清麗脫俗:1.邏輯 2. 控制。
- 邏輯用來解決實際的問題, 控制決定用什麼策略來解決問題,邏輯是真正意義上的解決問題的演算法
- 控制是一個程式流轉的方式,即程式執行的方式,並行還是序列,同步還是非同步,排程不同執行路徑或模組,資料之間的儲存關係。
邏輯是是處理什麼
,控制是怎麼做
,溝通方式是資料結構
舉例
表單驗證經常的做法是
function check(data) {
名字 = get(data, 名字)
if (名字為空 || 名字長度小於3) {
return 驗證失敗,名字非法
}
密碼 = get(data,密碼)
if (密碼為空 || 密碼長度小於8) {
return 驗證失敗,密碼非法
}
郵箱 = get(data,郵箱)
if (郵箱為空 || 郵箱格式不正確) {
return 驗證失敗,郵箱非法
}
...
return 驗證通過;
}
這個函式最終邏輯是驗證輸入資料的合法性,但是這樣其實就是把控制和邏輯耦合在一起了,隨著驗證欄位的增多,這個函式會越來越長,最終造成可讀性越來越差,越來越難維護
更好的分離兩者的方法是,定義一個表單驗證器,如下
var rules = {
名字: ["長度大於3"],
密碼: ["長度大於8"]
郵箱: ["email格式"]
...
]
};
if 失敗結果=checkRules(rules).執行(); 失敗結果不為空 {
return 驗證失敗,失敗結果
}
return 驗證通過
這樣通過描述驗證規則,得到了一種控制和邏輯之間的解耦,不用再在check裡邊各種if else了。
絕大多數程式複雜混亂的根本原因是業務邏輯和控制邏輯的耦合
二、物件導向、設計模式
物件導向、設計模式的重點就是:
- 使用介面抽象了具體的實現類,這樣其它類耦合的是介面而不是實現類,這就是多太,增加了程式的擴充套件性
- 介面也就是一種協議,就像HTTP協議一樣,瀏覽器和後端的程式都依賴於這一種協議,而不是具體的實現(如果是依賴具體實現,那麼瀏覽器就要依賴後端的程式語言或中介軟體了,這就太噁心了)。於是,瀏覽器和後端的程式就完全解除依賴關係,而去依賴一個標準的協議了,這也是Ioc/DIP的本質。
23個設計模式基本就是說了兩個物件導向的核心理念:面向介面程式設計、組合優於繼承
面向介面程式設計
- 使用者不需要知道資料型別、結構、演算法的細節
- 使用者不需要知道實現細節,只需要知道提供的介面
組合優於繼承
繼承需要給子類暴露一些父類的設計和實現細節,父類實現的改變會造成子類也需要改變,而組合則不存在這樣的弊端。
我們以為繼承主要是為了程式碼重用,但實際上在子類中需要重新實現很多父類的方法,繼承更多的應該是為了多型。
三、依賴倒置和控制反轉 (IoC/DIP)
簡單說就是要依賴於抽象介面,不要依賴於具體實現
這就是控制反轉,開關從以前裝置的專用開關,轉變到了控制電源的開關,而以前的裝置要反過來依賴開關廠宣告的電源介面
錢
從以前的以物易物,變成了依賴“錢”,所有的商品都依賴這個“錢”的交易協議,不用再互相依賴了,整個世界的動作就簡單了很多
開關和燈
有一個開關要控制一個燈的開和關,最直接的方法就是把開關和燈做到一起。
但是,如果有一天,我們發現這個開關可能還要控制別的不僅是燈泡的東西,就會發現開關耦合了燈泡這種類別,非常不得擴充套件。
解決方案就是,造開關工廠根據不需要關心要控制的東西是什麼,只做一個開關,功能就是把電接通和斷開,不管是手動的、聲控的還是光控、遙控的,開關廠和電燈廠依賴於一個標準的通電和斷電的介面。
造燈泡的工廠也不關心你用什麼樣的開關,只管把燈的電源介面做出來,開關廠和電燈廠依賴於一個標準通電和斷電的介面。
證券交易所
在交易的過程中,賣家向買家賣東西,一手交錢一手交貨,基本是要見面的,這個時候銀行出來做擔保,買家先把錢打到銀行,銀行讓賣家發貨,買家驗貨後,銀行再把錢打給賣家。
這就是反轉控制,買賣雙方把對對方的直接依賴和控制,反轉到了讓對方來依賴一個標準的交易模型的介面。