熟妇人妻中文字幕无码老熟妇福州江閩儀器技術有限公司
·
·
産品搜索(suo):

技(ji)術交流

周(zhou)立功:設計(ji)良好的程(cheng)序接口👩🏽‍🐰‍👩🏿熟妇人妻中文字幕无码老熟妇👹需(xu)注意的5個(ge)事項
來源(yuan):   發布時間(jian):2025-11-21   浏覽量:65

周(zhou)立功教授(shou)數年之心(xin)血之作《程(cheng)序設計與(yu)數據結構(gou)》,電🧛🏾‍♀️子版🧑🏽‍🎄已(yi)😁無償性分(fen)享到電子(zi)工程師與(yu)高校群體(ti)。書🙉本内容(rong)公開後,在(zai)電子行業(ye)掀起一片(pian)學習熱潮(chao)。經周立功(gong)教授授權(quan),特對本書(shu)内容進行(hang)連載,願共(gong)勉之。

第一(yi)章爲程序(xu)設計基礎(chu),本文爲1.5.2/1.5.3共(gong)性與可變(bian)性分析:建(jian)立抽象🏊🏾‍♀️和(he)建立接口(kou)。

>>>> 1.5.2 建立抽象(xiang)

抽象化的(de)目的是使(shi)調用者無(wu)需知道模(mo)塊的内部(bu)細節,隻👺需(xu)要知道模(mo)塊或函數(shu)的名字,因(yin)此将其稱(cheng)💞爲黑盒化(hua)。調用者隻(zhi)需要知道(dao)黑盒子的(de)輸入和輸(shu)出,而過程(cheng)的細節是(shi)隐藏的。由(you)于建立了(le)一個由黑(hei)盒子組成(cheng)😵‍💫的系統,因(yin)⛹🏻‍♂️此複雜的(de)結構就被(bei)黑盒子隐(yin)藏起來了(le),則理解系(xi)統的整體(ti)結構就變(bian)得更容易(yi)了。

從概念(nian)的視角來(lai)看,建立抽(chou)象關注的(de)不是如何(he)實現,而是(shi)函數👩🏼‍❤️‍👨🏾要做(zuo)什麽,過早(zao)地關注實(shi)現細節,将(jiang)實現細🎅🏿節(jie)隐藏起來(lai),進而幫助(zhu)我們構建(jian)更易于修(xiu)改😌的軟件(jian)。因此,我們(men)首先應該(gai)選擇一個(ge)具有描述(shu)性👹的符合(he)需求的名(ming)字,雖然可(ke)以選擇的(de)名字有swapByte、swapWord和(he)swap,但😸swap更簡潔(jie)更貼切。其(qi)次,可以👱🏼‍♂️用(yong)一句話概(gai)念性地描(miao)述swap的數據(ju)抽象——swap是👿實(shi)現兩個數(shu)據交換的(de)函數。

顯然(ran),調用者僅(jin)需一般性(xing)地在概念(nian)層次上與(yu)實現者交(jiao)流,因爲調(diao)用者的意(yi)圖是如何(he)使用swap()實現(xian)兩個數據(ju)的交換,所(suo)以無需準(zhun)确地知道(dao)實現的細(xi)節。而具體(ti)如何完成(cheng)數據的交(jiao)換,這是在(zai)實現層次(ci)進行的。由(you)此可見,将(jiang)模塊的目(mu)的與實現(xian)分離的抽(chou)象揭示了(le)問題的本(ben)質,并沒有(you)提供解決(jue)方🛌🏻案。隻說(shuo)明需要做(zuo)什麽,并不(bu)🤶🏾會指出如(ru)何實現某(mou)個模塊。隻(zhi)要概念不(bu)變,調用者(zhe)與實現細(xi)🧑🏽‍❤️‍💋‍🧑🏻節的變化(hua)就徹底隔(ge)離了。當💌某(mou)個模塊完(wan)成編碼後(hou),隻要說明(ming)該模塊的(de)目的和參(can)數就可以(yi)使用它,無(wu)需知道具(ju)體的實現(xian)。

函數抽象(xiang)對團隊項(xiang)目非常重(zhong)要,因爲在(zai)團隊中必(bi)須使用其(qi)他成員編(bian)寫的模塊(kuai)。比如,編程(cheng)語言本身(shen)自帶的庫(ku)函數💫,由于(yu)已經~被預(yu)編譯,因此(ci)無法訪問(wen)它的源代(dai)碼。同時庫(ku)函數不一(yi)定是用C編(bian)寫的,因此(ci)🧑🏽‍🎄隻要知道(dao)其調用規(gui)👀範,就可以(yi)在程序中(zhong)毫無顧忌(ji)😸地使用這(zhe)個函數。實(shi)際上✡️,在使(shi)用scanf()函數的(de)過程中,我(wo)們考慮過(guo)scanf()是如👩🏽‍🐰‍👩🏿何實(shi)現的嗎?無(wu)關緊要。盡(jin)管不同系(xi)統實現scanf()的(de)方法可🤶🏾能(neng)不一樣,但(dan)其中💘的不(bu)同對于程(cheng)序員來說(shuo)是透明的(de)。

>>>> 1.5.3 建立接口(kou)

接口是由(you)公開訪問(wen)的方法和(he)數據組成(cheng)的,接口描(miao)述🧛🏾‍♀️了與模(mo)😌塊交互的(de)唯一途徑(jing)。最小化的(de)接口隻包(bao)含對🛀🏼于接(jie)口的任務(wu)非常重要(yao)的參數,最(zui)小化的接(jie)口便于學(xue)習如何與(yu)之交互,且(qie)隻需要理(li)解少量的(de)參數,同時(shi)易于擴展(zhan)🤶🏾和維護,因(yin)此設計良(liang)好的接口(kou)是一項重(zhong)要的技能(neng)。

>>> 1. 函數調用(yong)

(1)傳值調用(yong)

如何調用(yong)swap()函數呢?實(shi)參将值從(cong)主調函數(shu)傳遞給被(bei)🙈調函數,也(ye)許其調用(yong)形式是下(xia)面這樣的(de):
swap(a, b);

從黑盒視(shi)角來看,形(xing)參和其它(ta)局部變量(liang)都是函數(shu)私有🏊🏿‍♀️的,聲(sheng)明💁🏼‍♀️在不同(tong)函數中的(de)同名變量(liang)是完全不(bu)同的變量(liang),而且🛌🏻函數(shu)無法🔞直接(jie)訪問其它(ta)函數中的(de)變量,這種(zhong)限制訪問(wen)保護了數(shu)據的完整(zheng)性,黑盒發(fa)生了什麽(me)⛹🏻‍♂️對主調函(han)數是不可(ke)見的。

一個(ge)變量的有(you)效範圍稱(cheng)作它的作(zuo)用域,變量(liang)的作用域(yu)👱🏼‍♂️指可以通(tong)過變量名(ming)稱引用變(bian)量的區域(yu),在函數内(nei)部聲^明的(de)變量😁隻在(zai)該函數内(nei)部有效。當(dang)主調函數(shu)調用子函(han)數時,主函(han)數内聲明(ming)的變量在(zai)子函👯🏾‍♂️數内(nei)無效,子函(han)數内聲明(ming)的變量也(ye)隻在該子(zi)函數内部(bu)有效。

由于(yu)傳遞給函(han)數的是變(bian)量的替身(shen),因此改變(bian)函數參😍數(shu)對原始💞變(bian)量沒有影(ying)響。當變量(liang)傳遞給函(han)數時,變量(liang)的值被複(fu)制給函數(shu)👾參數。由此(ci)可見,通過(guo)“傳值調用(yong)”方式交換(huan)👱🏼‍♂️a、b的值,無法(fa)改變🏊🏾‍♀️主調(diao)函數相應(ying)變量的值(zhi)。

(2)傳址調用(yong)

如果希望(wang)通過被調(diao)函數将更(geng)多的值傳(chuan)回主調函(han)😥數而改變(bian)✡️主調函數(shu)中的變量(liang),則使用“傳(chuan)址調用”——将(jiang)&a、&b作爲實參(can)👀傳遞給形(xing)參。其調用(yong)形式如下(xia):
swap(&a, &b);

利用指針(zhen)作爲函數(shu)參數傳遞(di)數據的本(ben)質,就是在(zai)🤶🏾主調函數(shu)😸和被調函(han)數中,通過(guo)不同的指(zhi)針指向同(tong)一内👌存地(di)址訪問相(xiang)😍同的内存(cun)區域,即它(ta)們背後共(gong)享相同的(de)内存,從而(er)實現數據(ju)的傳遞和(he)交換。

>>> 2. 函數(shu)原型

函數(shu)原型是C語(yu)言的一個(ge)強有力的(de)工具,它讓(rang)編譯器💕捕(bu)獲在使用(yong)函數時可(ke)能出現的(de)許多錯誤(wu)或疏漏。如(ru)果編譯器(qi)沒有發現(xian)這些問題(ti),就很難察(cha)覺出來。函(han)數👌原型包(bao)括函數返(fan)回值的類(lei)型、函數名(ming)和形參列(lie)表(參數的(de)數量♌️和每(mei)個參🧛🏽數的(de)類型😈),有了(le)這些🤶🏾信息(xi),編譯器👿就(jiu)可以檢查(cha)函數調用(yong)與🤶🏾函數原(yuan)型是😝否匹(pi)配?比如,參(can)🙂‍↔️數的數量(liang)是否正确(que)?參數的類(lei)😁型是否匹(pi)配?如果類(lei)型不匹配(pei),編譯器會(hui)👽将實參的(de)類型轉換(huan)成形參的(de)類型。

(1)函數(shu)形參

通過(guo)程序清單(dan) 1.15可以看出(chu),其相同的(de)處理部分(fen)是2個int類值(zhi)👀的交換代(dai)碼,因此可(ke)以将數據(ju)交換代碼(ma)移到🧜🏼‍♀️swap()函數(shu)的實現中(zhong)👾,其可變的(de)數據由外(wai)部傳進來(lai)的參數應(ying)對。由于&a是(shi)指向int類型(xing)變量a的指(zhi)針,&b是指向(xiang)int類型變量(liang)b的指針,因(yin)此必^須将(jiang)p1、p2形參聲明(ming)爲指😁向int *類(lei)型的🔞指針(zhen)變量,即必(bi)須将存儲(chu)int類型值變(bian)量的地址(zhi)作爲實參(can)賦給指針(zhen)形參,實參(can)與形參才(cai)能匹配。其(qi)函數原型(xing)進化如下(xia):
swap(int *p1, int *p2);

(2)返回值的(de)類型

聲明(ming)函數時必(bi)須聲明函(han)數的類型(xing),帶返回值(zhi)的函數~類(lei)型應該與(yu)其返回值(zhi)類型相同(tong),而沒有返(fan)回值的函(han)數應👀該聲(sheng)明爲void。類型(xing)聲明是函(han)數定義的(de)一部分,函(han)數類型指(zhi)…的是返回(hui)值的✍🏻類型(xing),不是函數(shu)參數的類(lei)型。

雖然可(ke)以使用return返(fan)回值,但return隻(zhi)能返回一(yi)個值給主(zhu)調函😜數。比(bi)如,如果返(fan)回值爲整(zheng)數,則函數(shu)返回值的(de)類型爲int。當(dang)返回值爲(wei)int類型時,如(ru)果返回值(zhi)爲負數,則(ze)表示失敗(bai);如果返回(hui)值爲非負(fu)數,則表示(shi)🧑🏽‍❤️‍💋‍🧑🏻成功。當返(fan)回值爲bool類(lei)型時,如果(guo)返回值爲(wei)false,則表示失(shi)敗🛌🏻,如果返(fan)回值爲true,則(ze)表示成功(gong)。當返回~值(zhi)爲指針類(lei)型時,如果(guo)返回值爲(wei)NULL,則表👨‍🦰示失(shi)敗,否則返(fan)回一個有(you)效的指針(zhen)。

如果利用(yong)指針作爲(wei)參數傳遞(di)給函數,不(bu)僅可以向(xiang)函數傳入(ru)數據,而且(qie)還可以從(cong)函數返回(hui)多個值。因(yin)爲函數的(de)👋調用者和(he)函數都可(ke)以使用指(zhi)向同一内(nei)👽存地址的(de)指針,即使(shi)用🧑🏽‍❤️‍💋‍🧑🏻同一塊(kuai)内存,所以(yi)使用指針(zhen)作爲函數(shu)參數時就(jiu)是對同一(yi)數據進行(hang)讀寫操作(zuo)。這樣不僅(jin)可✋以傳入(ru)數據🛀🏼,還可(ke)以通過在(zai)函數内部(bu)🏃🏻‍♀️修改這些(xie)數據,将函(han)數的結果(guo)傳出給調(diao)用者。

當函(han)數的實參(can)是指針變(bian)量時,有時(shi)希望函數(shu)能通💁🏼‍♀️過指(zhi)針指向别(bie)處的方式(shi)改變此變(bian)量,則需要(yao)使用指向(xiang)指針的指(zhi)針作爲形(xing)參。

由于swap()無(wu)返回值,因(yin)此swap()返回值(zhi)的類型爲(wei)void,其函數原(yuan)型如下:
void swap(int *p1, int *p2);

其(qi)被解釋爲(wei)swap是返回void的(de)函數(參數(shu)是int *p1,int *p2)。

這是一(yi)個不斷叠(die)代優化的(de)過程,用戶(hu)隻需要知(zhi)道“函數名(ming)、傳入函數(shu)的參數和(he)函數返回(hui)值的類型(xing)”,就知道如(ru)何有效地(di)調用相應(ying)的函數。

>>> 3.  依(yi)賴倒置原(yuan)則

在面向(xiang)過程編程(cheng)中,通常的(de)做法是高(gao)層模塊調(diao)用🧑🏽‍❤️‍💋‍🧑🏻低層模(mo)塊,其💞目的(de)之一就是(shi)要定義子(zi)程序層次(ci)結構。當高(gao)層模塊依(yi)賴于低層(ceng)模塊時,對(dui)低層模塊(kuai)的改動會(hui)直接影響(xiang)高層模塊(kuai),從而迫使(shi)它們依次(ci)做出修改(gai)。如果高層(ceng)模塊獨立(li)于低層模(mo)塊,則高層(ceng)模塊更容(rong)易重用,這(zhe)就是分層(ceng)架構設計(ji)的核心原(yuan)則,即依賴(lai)倒置原⛹🏻‍♂️則(ze)(Dependence Inversion Principle,DIP):

● 高層模塊(kuai)不應該依(yi)賴低層模(mo)塊,兩者都(dou)應該依賴(lai)⛹🏻‍♂️于抽象接(jie)口;

● 抽象接(jie)口不應該(gai)依賴于細(xi)節,細節應(ying)該依賴抽(chou)象接👋口。

當(dang)在分層架(jia)構中使用(yong)依賴倒置(zhi)原則時,将(jiang)會發現“不(bu)💘再存在分(fen)層”的概念(nian)了。無論是(shi)高層還是(shi)低層,它😜們(men)都😘依賴于(yu)抽象接口(kou),好像将整(zheng)個分層架(jia)構推平一(yi)樣。

其實從(cong)“Hello World”程序開始(shi),我們就已(yi)經在使用(yong)stdio.h包含的“抽(chou)象接口”了(le),即👽以後凡(fan)是用#include文件(jian)的擴展名(ming)叫.h(頭文件(jian))。如果源代(dai)碼中要用(yong)到~stdio标準💯輸(shu)入輸出函(han)數時,那麽(me)就要包含(han)這個頭文(wen)件,比👾如,“scanf("%d",&i);”函(han)數,其目的(de)😵‍💫是告訴編(bian)譯器要使(shi)用stdio庫。庫是(shi)一種工具(ju)的集合,這(zhe)些工具是(shi)由其它程(cheng)序員編寫(xie)的,用于實(shi)現特定的(de)功能。盡管(guan)實現者無(wu)需關心用(yong)戶将如何(he)使用庫,且(qie)不會直接(jie)開^放源代(dai)碼給用戶(hu)使用,但必(bi)須給用🏃🏻‍♀️戶(hu)提供調用(yong)函數所需(xu)要的信息(xi)。顯然隻要(yao)将頭文件(jian)開放給用(yong)戶👩🏽‍🐰‍👩🏿,即可讓(rang)用戶了解(jie)接口👯🏾‍♂️的所(suo)有細節,詳(xiang)見程序清(qing)單 1.16。

程序清(qing)單 1.16 swap數據交(jiao)換接口(swap.h)
1     #ifndef  _SWAP_H
2     #define  _SWAP_H
3     // 前(qian)置條件:實(shi)參必須是(shi)int類型變量(liang)的地址
4     // 後(hou)置條件:p1、p2作(zuo)爲輸出參(can)數,改變主(zhu)調函數中(zhong)相應的變(bian)量
5     void swap(int *p1, int *p2);
6     // 調用形(xing)式:swap(&a, &b)
7     #endif

其中,每(mei)個頭文件(jian)都指出了(le)一個用戶(hu)可見的外(wai)部函數👨‍🦰接(jie)🔞口,主要包(bao)括函數名(ming)、所需的參(can)數、參數的(de)類型和返(fan)回結果的(de)類型。其中(zhong),swap是庫的名(ming)字,程序清(qing)單 1.16(1~2)與(8)是幫(bang)助編譯器(qi)記錄它所(suo)讀取的接(jie)㊙️口,當寫一(yi)個😌接口時(shi),必須包含(han)#ifndef、#define和#ednif。#include行部分(fen)僅當接口(kou)本😘身需要(yao)其它庫時(shi)才使用,它(ta)由标準的(de)#include行組成。程(cheng)序清單 1.16(6)接(jie)口項表示(shi)庫輸出的(de)函數的原(yuan)型、常量和(he)類型等。不(bu)管你是否(fou)理🔞解,這些(xie)👩🏽‍🐰‍👩🏿行是接口(kou)的模闆文(wen)件,這就是(shi)信息隐藏(cang)。

>>> 4. 前/後置條(tiao)件

處理信(xin)息隐藏還(hai)涉及到另(ling)一個技術(shu),那就是使(shi)用前置😌條(tiao)件和後置(zhi)條件描述(shu)函數的行(hang)爲。在編寫(xie)一個完整(zheng)的函數定(ding)義時,需👼🏾要(yao)描述該函(han)數是如何(he)執行計算(suan)的。但在使(shi)用函數時(shi),隻需考慮(lü)該函數能(neng)做什麽,無(wu)需🧑🏽‍🎄知道是(shi)如何完成(cheng)的。當不知(zhi)道函數是(shi)如何實現(xian)時,就是在(zai)使用一種(zhong)名爲過程(cheng)抽象的信(xin)息隐藏形(xing)式,它💌抽象(xiang)掉的是函(han)數如何工(gong)作的細節(jie)。計算機科(ke)學家使用(yong)“過程”表示(shi)任意指😘令(ling)集,因此使(shi)用術😜語過(guo)程抽象。過(guo)程👱🏼‍♂️抽象是(shi)一種強大(da)的工具,使(shi)得我們一(yi)次隻考慮(lü)一個而不(bu)是所有的(de)函數,從而(er)使問題求(qiu)解簡單化(hua)。

爲了使描(miao)述更準确(que),則需要遵(zun)循固定的(de)格式,它包(bao)含兩部分(fen)👩🏼‍❤️‍👨🏾信息:函數(shu)的前置條(tiao)件和後置(zhi)條件。前置(zhi)條件就是(shi)🧎🏻‍♀️‍➡️調用該函(han)數必須成(cheng)立的條件(jian),當函數被(bei)調用時,該(gai)語句給出(chu)要求爲真(zhen)的條件。除(chu)非前置條(tiao)件爲真,否(fou)則無法保(bao)證函數能(neng)正确執行(hang)。在調用swap()函(han)數時,實參(can)必須是int類(lei)型變量的(de)地址,這是(shi)調用者的(de)職責。通常(chang)在💘函數開(kai)始處檢查(cha)是否滿足(zu)?如果不滿(man)足,說明調(diao)用代碼有(you)問題,抛出(chu)一個異常(chang)。

後置條件(jian)就是該操(cao)作完成後(hou)必須成立(li)的條件,當(dang)函數🙉調👽用(yong)時😥,如果函(han)數是正确(que)的,而且前(qian)置條件爲(wei)真,那麽該(gai)👩‍🍼函數調用(yong)👩‍🍼将可以執(zhi)行完成。當(dang)函數調用(yong)完成後,後(hou)置條件爲(wei)真。如果不(bu)滿足後置(zhi)條件,則說(shuo)明業務邏(luo)輯有問題(ti)。

當滿足調(diao)用swap()函數的(de)前置條件(jian)時,必須同(tong)時确保其(qi)結👋束時滿(man)足它的後(hou)置條件,其(qi)後置條件(jian)是被調函(han)數将返回(hui)值傳回主(zhu)調函數,改(gai)變主調函(han)數中變量(liang)👿的值。

前後(hou)置條件不(bu)隻是概括(kuo)地描述函(han)數的行爲(wei),聲明這些(xie)條👹件應該(gai)是設計任(ren)何函數的(de)第一步。在(zai)開始考慮(lü)某個函數(shu)😸的算法和(he)✋代碼之前(qian),應該寫出(chu)該函數的(de)原型,其中(zhong)包括函^數(shu)的返回類(lei)型、名稱和(he)參數列表(biao),最後緊跟(gen)一個分号(hao)。直接來自(zi)于用👽戶的(de)輸入👌不能(neng)作爲前置(zhi)條件,通常(chang)前/後置條(tiao)件😺都可以(yi)轉化爲assert語(yu)句。編寫函(han)數原型時(shi),應該以注(zhu)釋的形式(shi)描述該函(han)數的前置(zhi)條件和後(hou)👿置條件。

事(shi)實上,前置(zhi)條件和後(hou)置條件在(zai)使用函數(shu)的程序員(yuan)和編👿寫函(han)🧛🏽數的程序(xu)員之間形(xing)成了一個(ge)契約,也就(jiu)是爲什麽(me)需要這個(ge)函數?接口(kou)通過前置(zhi)條件和後(hou)置條件以(yi)契約的形(xing)式表達需(xu)求,承諾在(zai)滿足前置(zhi)條件時開(kai)始,按照程(cheng)序的流程(cheng)運行,系統(tong)就能到🏊🏿‍♀️達(da)後置條件(jian)。

雖然注釋(shi)是一種很(hen)好的溝通(tong)形式,但在(zai)代碼可以(yi)傳遞意圖(tu)的地方不(bu)要寫注釋(shi)。因爲代碼(ma)解釋做了(le)什麽,再注(zhu)釋也沒有(you)👩🏽‍🐰‍👩🏿什麽✋用處(chu),相反注釋(shi)要說明爲(wei)什麽會☠️這(zhe)樣寫代碼(ma)?

>>> 5. 開閉原則(ze)

接口僅需(xu)指明用戶(hu)調用程序(xu)可能調用(yong)的标識符(fu),應盡👋可能(neng)地将算法(fa)以及一些(xie)與具體的(de)實現細節(jie)無關💕的信(xin)💕息隐藏起(qi)來,這樣用(yong)戶在調用(yong)程序時也(ye)就不必依(yi)賴特^定的(de)實💕現細節(jie)了。當接口(kou)一旦發布(bu)後,也就不(bu)能改變了(le),因爲改變(bian)接口勢必(bi)引起用戶(hu)✡️程序的改(gai)變👧🏾。如果此(ci)前定👀義的(de)接口滿足(zu)不了需求(qiu),怎麽辦?隻(zhi)能擴展新(xin)的接口,但(dan)不能修改(gai)或廢除原(yuan)有的接口(kou)💌,這就是“對(dui)修改關閉(bi),對擴💞展開(kai)放”的開閉(bi)🧜🏼‍♀️原則(Open-Closed Princple,OCP)。顯然(ran),依賴倒置(zhi)原則更加(jia)精确的定(ding)義就是面(mian)向接口的(de)👩‍🍼編程,它是(shi)實🧑🏽‍❤️‍💋‍🧑🏻現開閉(bi)原則的重(zhong)要途徑。如(ru)😍果DIP依賴倒(dao)置原則沒(mei)有實現,就(jiu)别想實現(xian)對擴展開(kai)🎅🏿放,對修改(gai)關閉。

聯系(xi)我們站(zhan)點地圖 丨(shu) 友情鏈接(jie)工作機(ji)會
聯系地(di)址:福州市(shi)八一七中(zhong)路茶亭國(guo)際 郵編:350004 電(dian)話:0591-
Copyright © 2011-2012 All Right Reserved 京ICP證000000号(hao)

·
·
 
·
·
·
·
·