1. 程式人生 > 實用技巧 >《編寫可讀程式碼的藝術》第10章 抽取不相關的子問題

《編寫可讀程式碼的藝術》第10章 抽取不相關的子問題

所謂工程學就是把大問題拆成小問題,再把這些問題的解決方案放回一起。把這條原則應用於程式碼會使程式碼更健壯且更易讀。

本章建議是:積極發現並抽取出不相關的子邏輯。

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)

總結:把專案專有程式碼和一般程式碼(使之成為輔助函式)分開。