網上對於內聚和耦合的資料太多,這里結合我的感受和其他人的答案http://blog.csdn.net/zhiquan/article/details/4255161談談自己的理解
以下是我對內聚和耦合的理解(例子來源於生活)。
1.內聚:
i.偶然內聚:如果一個模塊的各成分之間毫無關系,則稱為偶然內聚。
eg.在敲代碼時,我們通常對一段代碼進行初始化function init(){}。而對各個模塊進行的初始化代碼通常都是沒有關系的,我們將這些代碼包裝成一個模塊,此時這個模塊就是偶然內聚的(楊老師在課上提出過這種內聚方式)。
ii.邏輯內聚。幾個邏輯上相關的功能被放在同一模塊中,則稱為邏輯內聚。如一個模塊讀取各種不同類型外設的輸入。盡管邏輯內聚比偶然內聚合理一些,但邏輯內聚的模塊各成分在功能上並無關系,即使局部功能的修改有時也會影響全局,因此這類模塊的修 改也比較困難。
eg.通過模塊讀取參數不同來執行不同的方法,我感覺類似於函數的重載。在我的快樂運算中有通過傳入的參數判斷執行的具體方法。此時屬於邏輯內聚。代碼自:https://github.com/yanyige/CourseWork/blob/master/Week6/js/generation.js):
其中,通過傳入的參數來確定生成算式的不同。
iii.時間內聚。如果一個模塊完成的功能必須在同一時間內執行(如系統初始化),但這些功能只是因為時間因素關聯在一起,則稱為時間內聚。
eg.這里例子同偶然內聚,將沒有關系(只是時間因素的關系)的代碼包裝到一起,構成一個代碼塊。
(4) 過程內聚。如果一個模塊內部的處理成分是相關的,而且這些處理必須以特定的次序執行,則稱為過程內聚。
eg.在快樂運算中,顯示每條答案時候必須先計算所有題目(每次生成5道題)的答案,再依次顯示到相應位置中。此時,先生成,再計算,最后顯示,形成了過程內聚。代碼自:https://github.com/yanyige/CourseWork/blob/master/Week6/js/generation.js):
function showFormula(items) { //顯示公式並且計算答案 for(var j = 0 ; j < items.length ; j++){ var str = items[j]; var strFormula = transforFraction(str); var text = document.getElementById("problem-table").children[0].children; text[j].children[1].innerHTML = strFormula; // console.log('strFormula = '+ strFormula); var S1 = [] // 保存運算符的棧 var S2 = [] // 保存中間結果的棧 for (var i = 0; i < str.length; i++) { // if (!isNaN(str[i])){ if(str[i] instanceof Fraction){ S2.push(str[i]); }else if(isOperate(str[i])){ if(!S1.length){ S1.push(str[i]); } else{ var s1Top = S1.pop(); S1.push(s1Top); if(s1Top == '('){ S1.push(str[i]); } else{ var prior1 = getPriorty(s1Top); var prior2 = getPriorty(str[i]); if(prior1 < prior2){ S1.push(str[i]); }else{ var tempOp = S1.pop(); S2.push(tempOp); i --; } } } }else if(str[i] == '('){ S1.push(str[i]); }else if(str[i] == ')'){ var tempOp = S1.pop(); while(tempOp != '('){ S2.push(tempOp); tempOp = S1.pop(); } } } while(S1.length){ var tempOp = S1.pop(); S2.push(tempOp); } ANS = getAns(S2); // anss.push(Number(ANS.toFixed(2))); // allAnss.push(Number(ANS.toFixed(2))); anss.push(ANS); allAnss.push(ANS); } }
(5) 通信內聚。如果一個模塊的所有成分都操作同一數據集或生成同一數據集,則稱為通信內聚。
eg.在快樂運算中,一次“小試牛刀”中的題目保存var allFormulas = [];這個數組中,每次計算或者添加算式均在操作此數組,這時形成了通信內聚。代碼自:https://github.com/yanyige/CourseWork/blob/master/Week6/js/generation.js):
var anss=[]; var ANS;//記錄結果 var youranss = []; var score = 0; var tScore = 0; var allFormulas = []; //通信內聚 var allAnss=[];//通信內聚 var allYourAnss=[];//通信內聚
(6) 順序內聚。如果一個模塊的各個成分和同一個功能密切相關,而且一個成分的輸出作為另一個成分的輸入,則稱為順序內聚。
eg.在快樂運算中,計算方法(function showFormula(items){})接受生成方法(function getFormula(MAXNUM, MAXDIGIT, PUNCTUATION, BRACKET, DENOMINATOR){})的返回值item。此時形成了順序內聚。
(7) 功能內聚。模塊的所有成分對於完成單一的功能都是必須的,則稱為功能內聚。
eg.在之前未完成作品計算器中,計算器中“取反”操作,“點擊數字”操作,“點擊運算符操作”,都是為了完成計算表達式。此時屬於功能內聚。
2.耦合
(1)內容耦合。當一個模塊直接修改或操作另一個模塊的數據,或者直接轉入另一個模塊時,就發生了內容耦合。此時,被修改的模塊完全依賴於修改它的模塊。
eg.我覺得在js的經典問題“閉包”中,產生了內容耦合。
(2)公共耦合。兩個以上的模塊共同引用一個全局數據項就稱為公共耦合。
eg.在以前寫代碼時,容易在全局定義一個變量,此時在不同的函數中使用這個變量,就產生了公共耦合。
(3)控制耦合。一個模塊在界面上傳遞一個信號(如開關值、標志量等)控制另一個模塊,接收信號的模塊的動作根據信號值進行調整,稱為控制耦合。
eg.經常我們會在代碼中做一個flag進行標記此時的狀態,當flag為0時執行部分代碼,flag為1時執行另一部分代碼,此時產生控制耦合。
(4)標記耦合。模塊間通過參數傳遞復雜的內部數據結構,稱為標記耦合。此數據結構的變化將使相關的模塊發生變化。
eg.兩個模塊之間傳遞復雜的數據結構(例如對象),就產生了標記耦合。
(5)數據耦合。模塊間通過參數傳遞基本類型的數據,稱為數據耦合。
eg.兩個模塊之間傳遞簡單的數據結構(例如number、boolean等),就產生了標記耦合。
(6)非直接耦合。模塊間沒有信息傳遞時,屬於非直接耦合。
eg.我覺得和初始化init()函數類似,若其中代碼毫無關聯,則產生了非直接耦合。
以上就是我對內聚和耦合的理解。