程序員, 你過度封裝了嗎?

過度封裝是程序員最容易犯的錯, 因為是否過度並沒有固定的數值標準, 只能是有經驗的程序員基於科學的判斷。 過度封裝的危害十分嚴重, 所以必須重視, 並且極力避免。

程序員, 你過度封裝了嗎?

什麼是”過度封裝”

首先, 什麼是”過度封裝”? 我們知道, 計算機科學領域最稱為經典也是最強大的思想便是遞歸, 分而治之。

但是, 遞歸本身最重要的因素是: 結束條件.

一生二, 二生三, 三生萬物, 總要有終止的條件吧? 不然一輛車不停地急馳, 你怎樣上車?

新手程序員, 特別是非科班出身的文科程序員, 最容易犯了過度封裝的錯誤的原因就是不知道何時適可而止, 腦筋往往不斷地分解分解再分解問題, 最後, 你看到的就是這個調用那個, 那個引用這個, 亂七八糟毫無頭緒, 三兩行代碼的函數比比皆是, 自以為封裝抽象, 其實是拿捏不好這個度。

一旦過度封裝, 直接的危害往往是寫了無數行代碼, 封裝了N多個類, 就是看不出一個完整的功能, 因為分裂起來收不住. 即使最終把功能實現了, 代碼維護性也讓人不忍直視。

如何判斷是否過度封裝?

如何判斷是否過度封裝? 如何避免過度封裝? 我認為, 只要掌握了一個原則, 時刻以這個原則為準繩, 那便幾乎不會犯過度封裝的錯誤。

這個原則便是”直觀優先”原則, 代碼邏輯以直觀為最優先的原則, 其它的原則均低於此原則, 即使有一百個考慮, 如果違反了直觀原則, 都必須放棄掉而優先保證直觀原則.

程序員, 你過度封裝了嗎?

舉一個例子:

function closeDialog() { login.close(); message.close(); ...close();}var action = { close: function () { closeDialog(); }, backout: function () { if (BACKOUT_ID) { ... } }};$(document).on('click', function (e){ var $that = $(e.target); for ( var k in action) { if ( $that.hasClass('action-'+k) ) { action[k].call(e.target); } }});

這樣的代碼就是過度封裝的經典體現!

首先, closeDialog() 這個函數不應該存在, 而應該被展開, 因為函數只被調用一次, 而且沒有邏輯上的獨立性的必要。

其次, 上面的函數通過跳轉表的方式來逃避直接的函數調用, 這是對跳轉表技術的極大濫用! if-else 加函數調用是最直觀的分支跳轉方式, 完全沒有必要在這個例子裡使用跳轉表技術.

先解釋一下什麼是跳轉表技術, 這是一個非常古老而基礎的計算機編程領域的技術. 跳轉表包含很多層含義, 簡單的說, 就是將邏輯代碼塊放到一個索引表中, 代碼編寫過程通過傳遞索引項來最終調用相應的邏輯代碼塊(因為多處引用)。

第一次聽到或者見到跳轉表技術的程序員的心情, 如果你想體驗的話, 你想想當你寫了無數的 if-else 之後, 你發現了 switch-case 時的心情, 或者是你第一次聽到函數指針這個事物時的心情。

但是, 像 js 之類高級語言, 已經把跳轉表技術, 直接融合到了語言的語法本身, 如類(class). 你不需要實現自己的跳轉表技術, 你只需要用好語言本身的特性即可。

所以, 上面的代碼應該改成:

$(document).on('click', function (e){var $that = $(e.target);if ( $that.hasClass('action-close') ) {login.close();message.close();...close();}if ( $that.hasClass('action-backout') ) {if (BACKOUT_ID) {...}}});

這是最直觀, 最正常, 人人都應該寫成這樣的代碼. 如果你還想顯式地使用查找表技術以體現自己牛逼, 我是說, 如果你真想裝逼的話, 你可以這樣寫:

var action = { close: function () { login.close(); message.close(); ...close(); }, backout: function () { if (BACKOUT_ID) { ... } }};$(document).on('click', function (e){ var $that = $(e.target); var func_name = $(that).attr('action'); if(func_name && action[func_name]){ action[func_name](); }});

如果都這樣寫了, 那和直接在 html 標籤裡寫 onclick 屬性有什麼區別? 難道通過 class 綁定事件就高級, 寫 onclick 指明回調函數的名字就不高級了?

程序員, 你過度封裝了嗎?

所以我勸你最好不要裝逼也別裝傻, 乖乖地有理有據有邏輯地寫代碼, 讓代碼的邏輯直觀起來, 不要過度封裝. 如果你內心封裝的慾望太強的話, 那我勸你學學 Go 語言, 把自己的思想強加到一種自己新發明的語言上來(我估計你沒那種本事). 不然, 直觀優先, 不要過度封裝。


分享到:


相關文章: