"高內聚、低耦合"
? ? 大家在談到面向對象編程的時候基本都是討論軟件的“高內聚、低耦合”的特點,這6個字也是算是成為了大部分評判代碼質量的一個標準,所以很多小伙伴一開始學習編程就會問道:"如何實現代碼的高內聚、低耦合"?我只想說這個問題還真不是三言兩句就能說清楚的,需要開發人員有一定的代碼量和軟件設計方面的開發實戰經驗。
? ? 不過既然提到了,作者就在這里談談自己的一些認知和看法,在討論一些問題的時候首先我們需要有設置一定的前提條件,否則一味的談論是沒有絲毫意義的,所以在分析前我們需要確定一個維度來看待問題,高內聚需要內部代碼和功能形成較強的關聯,而低耦合卻是要降低模塊間的內部依賴。
? ? 打個比方: 從人類角度看,每個人類都是一個單一的個體,其眼睛、鼻子、嘴巴等等形成了一個高度的內聚。而人與人之間又相互獨立,形成了一個較低的耦合。然而我們如果換一個角度來看來人類,那么人與人之間或許又形成了一個較強的內聚,人與其他動物之間又形成了較低的耦合,所以進一步類比代碼設計也就是一樣的道理了,面向對象其實也就為了實現這個目標而產生的,所以這里我們用萬能C來看看如何引入該思想:
3、用面向對象來玩C編程
? ? C面向對象編程之封裝
? ?對于封裝性,看過我的一些文章小伙伴應該有一個比較清晰的認識了吧,特別是講解結構體的時候,其中有個非常精妙的圖不知道大家還是否記得,如果不記得可以進去先看看,<【典藏】大佬們都在用的結構體進階小技巧>,結構體就是數據的集合,數據就是一個對象的屬性和方法,把共用的接口給外部使用,把私用的進行隱蔽,這樣就形成了良好的封裝,下面直接上最簡單的理解代碼:
示例代碼:
?
1#include?2#include? 3/************************************** 4?*?Fuction:?仿類? 5?* Author :(公眾號:最后一個bug)? 6?**************************************/ 7typedef?struct?_tag_Class 8{ 9????int?Val; 10????void?(*pmethod)(struct?_tag_Class*?pData); 11}sClass; 12 13/************************************** 14?*?Fuction:?方法? 15?* Author :(公眾號:最后一個bug)? 16?**************************************/ 17void?printfVal(sClass*?pObject) 18{ 19 20????printf("Object:%d ",pObject->Val); 21} 22/************************************** 23?*?Fuction:?main 24?* Author :(公眾號:最后一個bug)? 25?**************************************/ 26int?main(int?argc,?char?*argv[])?{ 27????//定義兩個對象? 28????sClass?stObject1; 29????sClass?stObject2; 30????//初始化對象屬性? 31????stObject1.Val?=?1; 32????stObject2.Val?=?2;? 33????stObject1.pmethod?=?printfVal; 34????stObject2.pmethod?=?printfVal; 35????//進行對象的使用? 36????stObject1.pmethod(&stObject1); 37????stObject2.pmethod(&stObject2); 38 39????printf("歡迎關注公眾號:最后一個bug "); 40????return?0; 41}
?
運行結果:
? ? C面向對象編程之繼承
? ?對于繼承性,就是父母有的我都有,并且還會有自己獨特的地方(數據),對于代碼里面無非就是屬性和方法了,結合結構體地址總是指向其結構體首地址的特點,利用父子結構體前面字段相同進行直接地址傳遞以后強制類型轉化便可以進行訪問,不過這僅僅只是單繼承,對于多繼承問題作者暫時不展開。
示例代碼:
?
1#include?2#include? 3?/************************************** 4??*?Fuction:?仿父類? 5??* Author :(公眾號:最后一個bug)? 6??**************************************/ 7?typedef?struct?_tag_Parent 8?{ 9????int?ParentVal;?//父類屬性? 10???void?(*pmethod)(struct?_tag_Parent*?pData);//父類方法? 11}sParent; 12 13/************************************** 14?*?Fuction:?仿子類? 15?* Author :(公眾號:最后一個bug)? 16**************************************/ 17typedef?struct?_tag_Child 18{ 19????sParent?ParentObj;//繼承父類數據和方法? 20????int?ChildVal;//子類特殊屬性? 21???void?(*pmethod)(struct?_tag_Child*?pData);//子類特殊方法? 22}sChild; 23 24/************************************** 25?*?Fuction:?父類方法? 26?* Author :(公眾號:最后一個bug)? 27?**************************************/ 28void?ParentprintfVal(sParent*?pObject) 29{ 30 31????printf("Parent?Object:%d ",pObject->ParentVal); 32} 33 34/************************************** 35?*?Fuction:?子類方法? 36?* Author :(公眾號:最后一個bug)? 37?**************************************/ 38void?ChildprintfVal(sChild*?pObject) 39{ 40 41????printf("Child?Object:%d ",pObject->ChildVal); 42} 43 44/************************************** 45?*?Fuction:?對接父類的公共接口? 46?* Author :(公眾號:最后一個bug)? 47?**************************************/ 48void?printfVal(sParent*?pObject) 49{ 50????pObject->pmethod(pObject); 51} 52 53/************************************** 54?*?Fuction:?main 55?* Author :(公眾號:最后一個bug)? 56?**************************************/ 57int?main(int?argc,?char?*argv[])?{ 58????//定義父類對象? 59????sParent?stParentObj; 60????sChild??stChildObj; 61 62????//構造(初始化對象和方法)? 63????stParentObj.ParentVal?=?10; 64????stParentObj.pmethod???=?ParentprintfVal; 65 66????//初始化子類對象和方法? 67????stChildObj.ParentObj.ParentVal??=?20; 68????stChildObj.ParentObj.pmethod????=?ParentprintfVal; 69????stChildObj.ChildVal?????????????=?11; 70????stChildObj.pmethod??????????????=?ChildprintfVal; 71 72????//調用公共的外部接口? 73????printfVal((sParent*)&stParentObj); 74????printfVal((sParent*)&stChildObj); 75 76????printf("歡迎關注公眾號:最后一個bug "); 77????return?0; 78}
?
運行結果:
? ? C面向對象編程之多態
? ??多態簡單一點說就是一個接口可以產生多種狀態處理,上一節其實也說明了這個特性,不過C++中的多態來自編譯的多態和運行時的多態,比如重載包括類重載和函數重載屬于編譯多態、虛函數等等屬于運行時多態,如果完全用C來模擬其實現還是相對比較復雜的,不過我們的目的僅僅只是說引入面向對象的一些思路來指導C編程,這里對于C編程就簡單一點實現函數重載,在C中通過傳遞參數就能夠實現一個函數的多態,不過這個傳參可能需要更加靈活一點,上代碼:
示例代碼:
?
1#include?2#include? 3/************************************** 4?*?Fuction:?任意數據結構? 5?* Author :(公眾號:最后一個bug)? 6?**************************************/ 7typedef?struct?_tag_Data 8{ 9????void*?pdata; 10????void?(*method)(struct?_tag_Data*?pData); 11}sData; 12 13/************************************** 14?*?Fuction:?具體實現1? 15?* Author :(公眾號:最后一個bug)? 16?**************************************/ 17void?Add(sData?*pData)? 18{ 19????int?*?Data?=?(int?*)pData->pdata; 20????printf("Add?=?%d ",(Data[0]?+?Data[1])); 21} 22 23/************************************** 24?*?Fuction:?具體實現2 25?* Author :(公眾號:最后一個bug)? 26?**************************************/ 27void?Sub(sData?*pData)? 28{ 29????int?*?Data?=?(int?*)pData->pdata; 30 31????printf("Sub?=?%d ",(Data[0]?-?Data[1])); 32} 33 34/************************************** 35?*?Fuction:?多態函數? 36?* Author :(公眾號:最后一個bug)? 37?**************************************/ 38void??Cal(sData?*pData)? 39{ 40??pData->method(pData); 41} 42 43/************************************** 44?*?Fuction:?main 45?* Author :(公眾號:最后一個bug)? 46?**************************************/ 47int?main(int?argc,?char?*argv[])?{ 48 49????int?Array[2]?={4?,2}; 50????sData?stData1; 51????sData?stData2; 52 53????stData1.pdata??=?(void*)Array; 54????stData1.method?=?Add; 55 56????stData2.pdata??=?(void*)Array; 57????stData2.method?=?Sub; 58 59?????Cal(&stData1); 60?????Cal(&stData2); 61 62????printf("歡迎關注公眾號:最后一個bug "); 63????return?0; 64}
?
運行結果:
4、最后小結
? ? 今天用C引出面向對象就講這么多吧,因為很多小伙伴沒有系統學習過C++語言,可能對于面向對象的理解不是特別形象,所以作者上面也只是簡單的是C模擬了面向對象編程的“冰上一角",更多實現作者還會在后期的文章進行闡述,這里就簡單給大家嘗個鮮。
????目前也存在非常多新型的編程設計模式,最終的編程我們還是要落在解決具體的問題、滿足用戶需求上來,就像一個簡單的設計其實根本就不需要有太多高級編程技巧的。然而對于嵌入式應用方面大部分的軟件設計還并沒有發展到面向對象思路無法勝任的地步。
?
評論