<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          C語(yǔ)言程序也有內(nèi)聚和耦合

          共 8954字,需瀏覽 18分鐘

           ·

          2024-06-16 22:10

             
              關(guān)注、星標(biāo)公眾號(hào),直達(dá)精彩內(nèi)容
          來(lái)源 | 網(wǎng)絡(luò)素材



          一、原理篇

          在軟件工程中,模塊的內(nèi)聚和耦合是度量模塊化質(zhì)量的標(biāo)準(zhǔn)之一。內(nèi)聚是指模塊的功能強(qiáng)度的度量,即一個(gè)模塊內(nèi)部各個(gè)元素彼此結(jié)合的緊密程度的度量。若一個(gè)模塊內(nèi)各元素(語(yǔ)名之間、程序段之間)聯(lián)系的越緊密,則它的內(nèi)聚性就越高。

          耦合是程序中各模塊之間相互聯(lián)系緊密程度的一種度量。各模塊之間聯(lián)系越緊密,其耦合性就越強(qiáng)。模塊間耦合高低取決于模塊間接口的復(fù)雜性、調(diào)用的方式及傳遞的信息。

          在程序設(shè)計(jì)中提倡的是高內(nèi)聚低耦合。所謂高內(nèi)聚,是指模塊是由相關(guān)性很強(qiáng)的代碼組成,只負(fù)責(zé)一項(xiàng)任務(wù),也就是常說(shuō)的單一責(zé)任原則,這樣的模塊,無(wú)論從設(shè)計(jì)、實(shí)現(xiàn)還是閱讀,都能體現(xiàn)出其保持專(zhuān)一性帶來(lái)的好處。

          而低耦合,是指模塊之間盡可能的使其獨(dú)立存在,模塊之間不產(chǎn)生聯(lián)系不可能,但模塊與模塊之間的接口應(yīng)該盡量少而簡(jiǎn)單。這樣,高內(nèi)聚從整個(gè)程序中每一個(gè)模塊的內(nèi)部特征角度,低耦合從程序中各個(gè)模塊之間的關(guān)聯(lián)關(guān)系角度,對(duì)我們的設(shè)計(jì)提出了要求。

          程序設(shè)計(jì)和軟件工程發(fā)展過(guò)程中產(chǎn)生的很多技術(shù)、設(shè)計(jì)原則,都可以從內(nèi)聚和耦合的角度進(jìn)行解讀。作為C語(yǔ)言程序設(shè)計(jì)的初學(xué)者,結(jié)合當(dāng)前對(duì)于函數(shù)的理解可達(dá)到的程度,我們探討一下如何做到高內(nèi)聚低耦合。

          針對(duì)低耦合。耦合程度最低的是非直接耦合,指兩個(gè)函數(shù)之間的聯(lián)系完全是通過(guò)共同的調(diào)用函數(shù)的控制和調(diào)用來(lái)實(shí)現(xiàn)的,耦合度最弱,函數(shù)的獨(dú)立性最強(qiáng)。

          但一組函數(shù)之間沒(méi)有數(shù)據(jù)傳遞顯然不現(xiàn)實(shí),次之追求數(shù)據(jù)耦合,調(diào)用函數(shù)和被調(diào)用函數(shù)之間只傳遞簡(jiǎn)單的數(shù)據(jù)參數(shù),例如采用值傳遞方式的函數(shù)。

          有些函數(shù)數(shù)在調(diào)用時(shí),利用形式參數(shù)傳地址的方式,在函數(shù)體內(nèi)通過(guò)指針可以修改其指向的作用域以外的存儲(chǔ)單元,這構(gòu)成了更強(qiáng)的耦合,稱(chēng)為特征耦合,在這里,使函數(shù)之間產(chǎn)生聯(lián)系的是地址這樣的特征標(biāo)識(shí)。另外,有兩個(gè)函數(shù)可能會(huì)打開(kāi)同一個(gè)文件進(jìn)行操作,這也構(gòu)成了特征耦合的一種形式。

          更強(qiáng)的耦合是外部耦合,這里,一組模塊都訪問(wèn)同一全局變量,而且不通過(guò)參數(shù)表傳遞該全局變量的信息,當(dāng)發(fā)現(xiàn)程序執(zhí)行結(jié)果異常時(shí),很難定位到是在哪個(gè)函數(shù)中出了差錯(cuò)。不少初學(xué)者覺(jué)得參數(shù)傳遞麻煩,將要處理的數(shù)據(jù)盡可能地定義為全局變量,這樣,函數(shù)之間的接口簡(jiǎn)單了,但形成的是耦合性很強(qiáng)的結(jié)構(gòu)。

          在C語(yǔ)言中,還可以通過(guò)靜態(tài)局部變量,在同一個(gè)程序的兩次調(diào)用之間共享數(shù)據(jù),這也可以視為是一種外部耦合,只不過(guò)靜態(tài)局部變量的作用域限于函數(shù)內(nèi)部,其影響也只在函數(shù)內(nèi)部,耦合程度比使全局變量也還是弱很多。由此,我們可以理解前述在使用全局變量、靜態(tài)局部變量時(shí)提出的“用在合適的時(shí)候,不濫用”的原則。

          針對(duì)高內(nèi)聚。內(nèi)聚程度最高的是功能內(nèi)聚,模塊內(nèi)所有元素的各個(gè)組成部分全部都為完成同一個(gè)功能而存在,共同完成一個(gè)單一的功能,模塊已不可再分。這樣的函數(shù)功能非常清晰、明確,一般出現(xiàn)在程序結(jié)構(gòu)圖的較低被調(diào)用的層次上。

          次之的是順序內(nèi)聚,一個(gè)函數(shù)中各個(gè)處理元素和同一個(gè)功能密切相關(guān),通常前一個(gè)處理元素的輸出是后一個(gè)處理元素的輸入。對(duì)于這樣的函數(shù),如果不致于產(chǎn)生高耦合的話(huà),可以分開(kāi)兩個(gè)函數(shù)實(shí)現(xiàn)。

          有的函數(shù),其中的不同處理功能僅僅是由于都訪問(wèn)某一個(gè)公用數(shù)據(jù)而發(fā)生關(guān)聯(lián),這稱(chēng)為通信內(nèi)聚和信息內(nèi)聚,內(nèi)聚程度進(jìn)一步下降。內(nèi)聚程度再低的情況就不再一一列舉,最差的偶然內(nèi)聚中,一個(gè)函數(shù)內(nèi)的各處理元素之間沒(méi)有任何聯(lián)系,只是偶然地被湊到一起。

          可以想像這樣的模塊東一榔頭西一錘子,類(lèi)似一個(gè)毫無(wú)凝聚力的團(tuán)伙,對(duì)應(yīng)的是低質(zhì)量??傊?,在解決問(wèn)題劃分函數(shù)時(shí),要遵循“一個(gè)函數(shù),一個(gè)功能”的原則,盡可能使模塊達(dá)到功能內(nèi)聚。

          要做到高內(nèi)聚低耦合,重點(diǎn)是要在寫(xiě)代碼之前花些時(shí)間做好設(shè)計(jì)。在下面的例子中,將討論結(jié)合具體的問(wèn)題,如何將以上的因素考慮進(jìn)去。

          二、示例篇

          本例受裘宗燕老師《從問(wèn)題到程序——程序設(shè)計(jì)與C語(yǔ)言引論啟發(fā)》。

          任務(wù) 輸出200以?xún)?nèi)的完全平方數(shù)(一個(gè)數(shù)如果是另一個(gè)整數(shù)的完全平方,那么我們就稱(chēng)這個(gè)數(shù)為完全平方數(shù),也叫做平方數(shù)),要求每隔5個(gè)數(shù)據(jù)要輸出一個(gè)換行。

          解決方案及點(diǎn)評(píng) 對(duì)于這個(gè)簡(jiǎn)單任務(wù),我們?cè)谝粋€(gè)main函數(shù)中完成了任務(wù)。程序如方案1:

          //方案1:內(nèi)聚性較高的單模塊實(shí)現(xiàn)方案
          #include <stdio.h>
          int main()
          {
              int m, num=0;
              for (m = 1; m * m <= 200; m++)
              {
                  printf("%d ", m * m);
                  num++;
                  if (num%5==0)
                      printf("\n");
              }
              return 0;
          }

          由于任務(wù)本身簡(jiǎn)單,將之在一個(gè)main函數(shù)中實(shí)現(xiàn)后,這個(gè)函數(shù)的內(nèi)聚程度接近功能內(nèi)聚,已經(jīng)相當(dāng)高了,就任務(wù)本身,不需再進(jìn)行分解。為使讀者能深入理解模塊質(zhì)量方面的技術(shù),我們將試圖將內(nèi)聚程序再提高一些,然后考察耦合程度不同的各種解決方案。

          要提高上面解決方案中函數(shù)(僅main一個(gè)函數(shù))的內(nèi)聚程度,我們考察程度的功能“找出完全平方數(shù)并輸出”——“找出完全平方數(shù)”和“輸出”這本身就是兩個(gè)功能,再細(xì)分輸出時(shí)還有“要求5個(gè)數(shù)據(jù)在一行”的要求,這些功能的實(shí)現(xiàn)細(xì)節(jié)都在一個(gè)函數(shù)當(dāng)中,可見(jiàn)是有余地再提高內(nèi)聚程度的。

          在實(shí)現(xiàn)的應(yīng)用中,幾乎所有的處理都可以分解為“輸入-計(jì)算-輸出”的模式,優(yōu)秀的解決方案往往至少要將這三個(gè)模塊都獨(dú)立出來(lái),對(duì)于“計(jì)算”模塊而言,其內(nèi)部不再包括輸入輸出,專(zhuān)門(mén)接受輸入的數(shù)據(jù),計(jì)算完成后返回結(jié)果即可。當(dāng)然,對(duì)于復(fù)雜的問(wèn)題,在各個(gè)環(huán)節(jié)上可能還需要再做分解。

          下面,我們探討將“找出完全平方數(shù)輸出”和“每5個(gè)數(shù)據(jù)后換行”分開(kāi)實(shí)現(xiàn)的方案。這樣的分解有助于提高內(nèi)聚性,與此同時(shí),分解后的兩個(gè)模塊間的耦合程度,成為我們要關(guān)注的焦點(diǎn)。

          現(xiàn)在將“找出完全平方數(shù)并輸出”的功能仍放在main函數(shù)中(獨(dú)立成為單獨(dú)的函數(shù)也可以,但不必要了),而“每5個(gè)數(shù)據(jù)后換行”的功能,設(shè)計(jì)一個(gè)名稱(chēng)為format的函數(shù),它每調(diào)用一次就輸出一個(gè)空格作為兩個(gè)完全平方數(shù)間的分隔,而每調(diào)用到第5次時(shí),輸出的是一個(gè)換行。這兩個(gè)模塊之間,需要有一個(gè)“現(xiàn)在是第幾次調(diào)用”的信息需要傳遞,不可能用耦合程度最松散的非直接耦合.我們考慮數(shù)據(jù)耦合,用簡(jiǎn)單形式參數(shù)傳值,得到方案2。

          //方案2:一個(gè)耦合度低,但不能完成功能要求的解決方案
          #include <stdio.h>
          void format(int);
          int main()
          {
              int m, num=0;
              for (m = 1; m * m <= 200; m++)
              {
                  printf("%d", m * m);
                  format(num);
              }
              return 0;
          }
          void format(int n)
          {
              n++;
              if (n%5==0)
                  printf("\n");
              else
                  printf(" ");
              return;
          }

          在這個(gè)程序結(jié)構(gòu)中,format與main函數(shù)的耦合程度為數(shù)據(jù)耦合。在main中定義了局部變量num,在一次都未輸出時(shí),置初值為0是合理的。在調(diào)用format時(shí),將num傳遞來(lái)的表示第幾次輸出(第幾個(gè)完全平方數(shù))的形式參數(shù)n,n自增1,然后再控制輸出空格或換行。

          然而分析和運(yùn)行程序發(fā)現(xiàn),“每隔5個(gè)數(shù)據(jù)輸出一個(gè)換行”的功能并未實(shí)現(xiàn)。因?yàn)樾问絽?shù)n在函數(shù)format內(nèi)的改變對(duì)應(yīng)的實(shí)在參數(shù)num占不同的內(nèi)存空間,n++修改的結(jié)果,對(duì)num無(wú)任何的影響,導(dǎo)致了在下一次調(diào)用時(shí),丟失了“輸出的是第幾個(gè)”的重要信息。一個(gè)補(bǔ)救的方法,是由format將變化后的n值作為返回值,再傳回給main函數(shù),得到如下方案3的程序:

          //方案3:利用了返回值使耦合度增大,但功能得以實(shí)現(xiàn)的方案
          #include <stdio.h>
          int format(int);
          int main()
          {
              int m, num=0;
              for (m = 1; m * m <= 200; m++)
              {
                  printf("%d", m * m);
                  num = format(num);
              }
              return 0;
          }
          int format(int n)
          {
              n++;
              if (n%5==0)
                  printf("\n");
              else
                  printf(" ");
              return n;
          }

          維持原函數(shù)返回值為void,而將參數(shù)改為傳地址,得到下面的方案4。這個(gè)方案的耦合度更高一些,但功能還是能夠?qū)崿F(xiàn)的。

          //方案4:傳地址實(shí)現(xiàn)功能的方案,耦合度更大
          #include <stdio.h>
          void format(int*);
          int main()
          {
              int m, num=0;
              for (m = 1; m * m <= 200; m++)
              {
                  printf("%d", m * m);
                  format(&num);
              }
              return 0;
          }
          void format(int *p)
          {
              (*p)++;
              if ((*p)%5==0)
                  printf("\n");
              else
                  printf(" ");
              return;
          }

          一定有人想到了用全局變量的解決方案。這樣,可以將num定義為全局變量,num的生存周期不再依賴(lài)于函數(shù)調(diào)用,其值也能在函數(shù)的調(diào)用之間保持不變(只要其間沒(méi)有另外給它賦值),從而可以完成傳遞信息的任務(wù)。這時(shí),format因?yàn)闊o(wú)需參數(shù)傳遞,可以設(shè)計(jì)為無(wú)參函數(shù),得到如下方案5的程序:

          //方案5:耦合度最高的全局變量方案
          #include <stdio.h>
          void format();
          int num=0;
          int main()
          {
              int m ;
              for (m = 1; m * m <= 200; m++)
              {
                  printf("%d", m * m);
                  format();
              }
              return 0;
          }
          void format()
          {
              num++;
              if (num%5==0)
                  printf("\n");
              else
                  printf(" ");
              return;
          }

          這是解決這個(gè)問(wèn)題的耦合程度最高的一個(gè)方案。將num定義為外部變量,意味著如果還有其他函數(shù),num是可以被任何函數(shù)修改的,當(dāng)發(fā) format 計(jì)數(shù)錯(cuò)誤時(shí),尋找錯(cuò)誤困難,而修改后又可能會(huì)帶來(lái)其他地方的錯(cuò)誤。在這么一個(gè)短小的程序中,這種方案可能尚可接受,當(dāng)程度的規(guī)模稍變大,可能帶來(lái)的問(wèn)題必須高度重視。因此,在實(shí)際應(yīng)用中,強(qiáng)調(diào)全局變量要慎用(不是不用)。

          考慮到num是在format中應(yīng)用的私用數(shù)據(jù)——只有format才關(guān)心這到底是第幾個(gè)數(shù)據(jù),main本來(lái)都不用關(guān)心的。這樣,可以考慮將num定義為format中的局部靜態(tài)變量,得到方案6的程序:

          //方案6:用靜態(tài)局部變量,耦合度偏高但封裝性最好的方案
          #include <stdio.h>
          void format();
          int main()
          {
              int m ;
              for (m = 1; m * m <= 200; m++)
              {
                  printf("%d", m * m);
                  format();
              }
              return 0;
          }
          void format()
          {
              static int num=0;
              num++;
              if (num%5==0)
                  printf("\n");
              else
                  printf(" ");
              return;
          }

          在這里,靜態(tài)局部變量num的作用域是局部的,定義在函數(shù)體里,封裝性在所有方案里是最好的,從而能保證信息的隱蔽性,避免其他函數(shù)無(wú)意的越權(quán)訪問(wèn);不過(guò),num的生存期是全局的,可以跨越函數(shù)的不同次調(diào)用,在兩次調(diào)用間傳遞信息,耦合程度(自己和自己的耦合)要高一些,但使main函數(shù)和format函數(shù)的耦合達(dá)到了最理想的程度,既保證了功能的正確,又保證了局部數(shù)據(jù)的安全性,表現(xiàn)出靜態(tài)局部變量的優(yōu)勢(shì)。綜上所述,在解決一個(gè)問(wèn)題時(shí),存在著諸多的方案。方案1可以接受,但希望提高內(nèi)聚性而做出改進(jìn);方案2用簡(jiǎn)單的參數(shù)傳值方式實(shí)現(xiàn)耦合程度低,但很可惜不能完成功能;在其他方案中,對(duì)于這個(gè)問(wèn)題,選擇的優(yōu)先順序是:

          方案6、方案3 > 方案4 > 方案5

          建議讀者回顧前面的內(nèi)容,想一想這樣排序的理由。在上述探討各個(gè)方案的過(guò)程中,我們應(yīng)該體會(huì)到在程序設(shè)計(jì)能力提高的過(guò)程中,不斷地學(xué)習(xí)新的技術(shù),懂得新的評(píng)判標(biāo)準(zhǔn),這也就是一個(gè)不斷拓寬眼蜀的過(guò)程。在稍后的練習(xí)中,不妨多想一些方案,也能夠從專(zhuān)業(yè)的角度評(píng)判方案的優(yōu)劣,最終做到的,就是出手就是最佳方案的專(zhuān)業(yè)水平。 

          原文鏈接:https://blog.csdn.net/sxhelijian/article/details/79401703

          版權(quán)聲明:本文來(lái)源網(wǎng)絡(luò),免費(fèi)傳達(dá)知識(shí),版權(quán)歸原作者所有。如涉及作品版權(quán)問(wèn)題,請(qǐng)聯(lián)系我進(jìn)行刪除。

          ????????????????  END  ???????????????

                

          關(guān)注我的微信公眾號(hào),回復(fù)“星球”加入知識(shí)星球,有問(wèn)必答。

                


          點(diǎn)擊“閱讀原文”查看知識(shí)星球詳情,歡迎點(diǎn)分享、收藏、點(diǎn)贊、在看。

          瀏覽 203
          1點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          1點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  高潮国产视频 | 激情国产 在线 | 蜜桃AV777 | 国语对白中文字幕第二页 | 97视频国产 |