《編寫可讀程式碼的藝術》第10章 抽取不相關的子問題
阿新 • • 發佈:2021-01-19
所謂工程學就是把大問題拆成小問題,再把這些問題的解決方案放回一起。把這條原則應用於程式碼會使程式碼更健壯且更易讀。
本章建議是:積極發現並抽取出不相關的子邏輯。
1. 純工具程式碼
1 //C++中沒有一個庫函式讀取整個檔案,所以不可避免地要寫以下的程式碼: 2 ifstream file(file_name); 3 // Calculate the file's size, and allocate a buffer of that size. 4 file.seekg(0, ios::end); 5 const int file_size = file.tellg(); 6 char* file_buf = new char [file_size]; 7 // Read the entire file into the buffer. 8 file.seekg(0, ios::beg); 9 file.read(file_buf, file_size); 10 file.close(); 11 12 //這就是一個工具程式碼,應該抽取到一個新函式中(例如ReadFileToString)。 13 //經過一段時間,你會建立起一組不錯的工具程式碼,可用於多個專案。
2. 其他多用途程式碼
1 ajax_post({ 2 url: 'http://example.com/submit',3 data: data, 4 on_success: function (response_data) { 5 var str = "{\n"; 6 for (var key in response_data) { 7 str += " " + key + " = " + response_data[key] + "\n"; 8 } 9 alert(str + "}"); 10 // Continue handling 'response_data' ... 11 }12 }); 13 14 //從中抽取出format_pretty可以使程式碼使用更簡單,更易讀。 15 //同時,功能的修改或新增也更簡單 16 var format_pretty = function (obj) { 17 var str = "{\n"; 18 for (var key in obj) { 19 str += " " + key + " = " + obj[key] + "\n"; 20 } 21 return str + "}"; 22 };
3. 簡化已有介面
1 var max_results; 2 var cookies = document.cookie.split(';'); 3 for (var i = 0; i < cookies.length; i++) { 4 var c = cookies[i]; 5 c = c.replace(/^[ ]+/, ''); // remove leading spaces 6 if (c.indexOf("max_results=") === 0) 7 max_results = Number(c.substring(12, c.length)); 8 } 9 10 //建立一個新的函式get_cookie 11 var max_results = Number(get_cookie("max_results"));
4. 按需重塑介面
1 user_info = { "username": "...", "password": "..." } 2 user_str = json.dumps(user_info) 3 cipher = Cipher("aes_128_cbc", key=PRIVATE_KEY, init_vector=INIT_VECTOR, op=ENCODE) 4 encrypted_bytes = cipher.update(user_str) 5 encrypted_bytes += cipher.final() # flush out the current 128 bit block 6 url = "http://example.com/?user_info=" + base64.urlsafe_b64encode(encrypted_bytes) 7 8 #抽取出url_safe_encrypt 9 def url_safe_encrypt(obj): 10 obj_str = json.dumps(obj) 11 cipher = Cipher("aes_128_cbc", key=PRIVATE_KEY, init_vector=INIT_VECTOR, op=ENCODE) 12 encrypted_bytes = cipher.update(obj_str) 13 encrypted_bytes += cipher.final() # flush out the current 128 bit block 14 return base64.urlsafe_b64encode(encrypted_bytes) 15 16 #真正的邏輯程式碼將變得非常簡單 17 user_info = { "username": "...", "password": "..." } 18 url = "http://example.com/?user_info=" + url_safe_encrypt(user_info)
5. 過猶不及
1 #對於上面的程式碼可能可以進一步拆分,但是這麼多小函式對可讀性是不利的 2 #因為讀者需要關注過多的東西,並且按照執行路徑跳來跳去 3 #如果專案其他部分需要這些小函式,那麼增加這些小函式是沒問題的 4 def make_cipher(): 5 return Cipher("aes_128_cbc", key=PRIVATE_KEY, init_vector=INIT_VECTOR, op=ENCODE) 6 7 def encrypt(data): 8 cipher = make_cipher() 9 encrypted_bytes = cipher.update(data) 10 encrypted_bytes += cipher.final() # flush out any remaining bytes 11 return encrypted_bytes 12 13 def url_safe_encrypt_str(data): 14 encrypted_bytes = encrypt(data) 15 return base64.urlsafe_b64encode(encrypted_bytes) 16 17 def url_safe_encrypt_obj(obj): 18 obj_str = json.dumps(obj) 19 return url_safe_encrypt_str(obj_str) 20 21 user_info = { "username": "...", "password": "..." } 22 url = "http://example.com/?user_info=" + url_safe_encrypt_obj(user_info)
總結:把專案專有程式碼和一般程式碼(使之成為輔助函式)分開。