>>>1.5.4實現(xiàn)接口
為了描述事物的完整性和相對封閉性,“封裝”就提上了日程,細節(jié)從此不需要再去關(guān)注。而封裝的傳統(tǒng)定義是數(shù)據(jù)隱藏,如果還是這樣看待封裝,則具有很大的局限性。應(yīng)該將封裝視為任何形式的隱藏,即發(fā)現(xiàn)變化將其封裝。封裝不僅可以隱藏數(shù)據(jù),而且可以隱藏實現(xiàn)和隱藏設(shè)計等所有的細節(jié)。
如果以更寬泛的方式看待封裝,其優(yōu)點是能夠帶來一種更好的分解程序的方法,于是封裝層自然而然地就成為了設(shè)計需要遵循的接口。封裝不會妨礙人們認識程序內(nèi)部具體是如何實現(xiàn)的,只是為了防止用戶寫出依賴內(nèi)部實現(xiàn)的代碼。進而強迫用戶在調(diào)用程序時,僅僅依賴于接口而不是內(nèi)部實現(xiàn),使抽象的概念接口和實現(xiàn)分離,將大大降低軟件維護成本。
C語言中的*.c文件就是接口功能的具體實現(xiàn),即用戶不可見的內(nèi)部實現(xiàn),簡稱實現(xiàn)。一個接口可以有多個實現(xiàn),它在發(fā)布后還可以改變、升級,因為它的改變不會對調(diào)用程序產(chǎn)生影響。大多數(shù)時候,*.c和*.h是成對出現(xiàn)的,一般來說,將某個子模塊的聲明放在*.h文件中,而將具體的實現(xiàn)放在對應(yīng)的*.c文件中。*.c文件可以通過引用一個或多個*.h文件,達到共用各種聲明的目的,但是*.h文件不可以引用*.c文件。
其實軟件包就是一個用來描述定義一個庫的軟件,其中*.h文件作為庫的接口,而實現(xiàn)這個庫可能有一個或多個*.c文件,每個*.c文件包含1個或多個函數(shù)定義,軟件包就是由*.h文件和*.c文件所組成的。這是一種良好的風(fēng)格,適用于任何大型程序和小型程序。
假設(shè)開發(fā)一個由多個文件組成的大型程序pgm,這樣就需要在每個*.c文件的頂部都放上這樣一行:
#include "pgm.h" //用戶自己編寫的庫文件
由此可見,通過共性分析使設(shè)計具有比較強的內(nèi)聚,其價值就是實現(xiàn)緊湊的設(shè)計。從而使調(diào)用者無需關(guān)注實現(xiàn)的細節(jié),實際上是函數(shù)的實現(xiàn)與使用它們的函數(shù)解耦了,swap()接口的實現(xiàn)程序清單 1.17。
程序清單1.17swap數(shù)據(jù)交換接口的實現(xiàn)(swap.c)
1 #include "swap.h"
2 void swap(int *p1, int *p2)
3 {
4 int temp;
5
6 temp = *p1; *p1 = *p2; *p2 = temp;
7 }
當(dāng)p1和p2分別指向變量a和b時,則p1和p2存儲的值就是&a和&b,即可用*p1和*p2表示a和b的值。如果寫成以下這種形式:
temp = p1;
則交換的不是a的值,而是a的地址(p1的值就是a的地址)。而函數(shù)要交換的是a和b的值,不是它們的地址。因此需要使用*運算符和指針,該函數(shù)才能訪問存儲在這些位置的值并改變它們。即指針允許將局部變量的地址傳給函數(shù),然后在函數(shù)中修改局部變量。
由此可見,當(dāng)將問題的“共性和可變性”分離開來,經(jīng)過簡化后發(fā)現(xiàn),穩(wěn)定不變的相同的處理部分(temp = *p1; *p1 = *p2; *p2 = temp;)都包含在抽象的模塊中,可變性分析所發(fā)現(xiàn)的變化的變量a和b由外部傳遞進來的參數(shù)應(yīng)對。從軟件設(shè)計學(xué)角度來看,共性和可變性分析原理自然而然地成為了面向過程編程的理論基石。
注意,編寫代碼必須遵循結(jié)構(gòu)化編程規(guī)則,即每個函數(shù)、函數(shù)中的每個代碼塊都應(yīng)該只有一個入口、一個出口。實際上,只有在大函數(shù)中,這些規(guī)則才會有明顯的好處。剛開始寫代碼時,都會冗長而復(fù)雜。有太多的縮進和嵌套循環(huán),有過長的參數(shù)列表,甚至還會有重復(fù)的代碼。需要不斷打磨這些代碼,分解函數(shù)、修改名稱、消除重復(fù),并保證測試通過。
有時我們并不關(guān)心指針所指向的變量的類型,此時可以使用并不指定具體數(shù)據(jù)類型的泛型指針void *。通常只允許相同類型的指針之間進行轉(zhuǎn)換,但泛型指針能夠轉(zhuǎn)換為任何類型的指針,反之亦然。比如,C標準庫中的memcpy()函數(shù)它將一段數(shù)據(jù)從內(nèi)存中的一個地方復(fù)制到另一個地方。由于memcpy()可能用于復(fù)制任何類型的數(shù)據(jù),因此將它的指針參數(shù)設(shè)定為void指針是非常合理的。比如,此前的swap()函數(shù),可以將它的參數(shù)改為void指針,則swap()就變成了一個可以交換任何類型數(shù)據(jù)的通用交換函數(shù),詳見程序清單1.18。
程序清單1.18swap()函數(shù)(void_data_swap.c)
1 #include
2 #include
3
4 int swap(void *x, void *y, int size)
5 {
6 void *temp;
7
8 if((temp = malloc(size)) == NULL)
9 return -1;
10 memcpy(temp, x, size); memcpy(x, y, size); memcpy(y, temp, size);
11 free(temp);
12 return 0;
13 }
>>>1.5.5使用接口
只要傳入待交換的變量的地址,即可確定如何通過接口調(diào)用它們,詳見程序清單1.19。
程序清單1.19 swap數(shù)據(jù)交換函數(shù)范例程序
1 #include
2 #include "swap.h"
3
4 int main(int argc, char *argv[])
5 {
6 int a = 1, b = 2;
7
8 printf("%d, %d\n", a, b);
9 swap(&a, &b);
10 printf("%d, %d\n", a, b);
11 return 0;
12 }
由此可見,抽象的接口隱藏了它的內(nèi)部細節(jié),用戶不再依賴具體的實現(xiàn)代碼,而是依賴于抽象接口。抽象的接口幾乎沒有細節(jié),沒有什么需要變化的,使抽象和細節(jié)彼此隔離,因此抽象的接口非常容易被重用,其深刻地揭示了抽象的生命力。
-
接口
+關(guān)注
關(guān)注
33文章
8918瀏覽量
153138 -
封裝
+關(guān)注
關(guān)注
128文章
8446瀏覽量
144687
原文標題:周立功:實現(xiàn)和使用易重用的抽象接口
文章出處:【微信號:ZLG_zhiyuan,微信公眾號:ZLG致遠電子】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
飛凌嵌入式ElfBoard ELF 1板卡-Regmap的優(yōu)勢
飛易通攜<飛易云>系統(tǒng)助力物聯(lián)網(wǎng)新變革!

易華錄智慧交管大模型實現(xiàn)交通數(shù)據(jù)價值的深度挖掘與應(yīng)用
系統(tǒng)建模與抽象層次:從模塊到物理實現(xiàn)

LabVIEW抽象消息使用教程(上)

利用FPGA實現(xiàn)USB 2.0通信接口

兆易創(chuàng)新榮獲2024全球電子成就獎年度微控制器/接口產(chǎn)品獎
智能選擇ADC/DAC可實現(xiàn)更好的軟件定義無線電設(shè)計

使用ADC12_A實現(xiàn)熱電偶接口

單CPU 雙項目開發(fā)實現(xiàn)更好的維護性和可行性應(yīng)用說明

優(yōu)易通無線DTU騰訊云通信實例

MSPM0-高級控制計時器有助于實現(xiàn)更好的控制和更好的數(shù)字輸出

克服設(shè)計難題-實現(xiàn)高性能接口

串行外設(shè)接口的菊花鏈實現(xiàn)

評論