產品開發這幾年(2)介面抽象

2021-06-20 03:08:18 字數 2692 閱讀 1819

軟體設計中各種介面隨處可見,如函式介面、子系統或模組之間的介面、不同產品之間的介面等,而介面抽象歷來是「仁者見仁,智者見智」。一般情況下,我們得到的只是一些介面抽象的基本原則、建議,而程式設計師在具體開發中則大有「天高任鳥飛」的趨勢,不同程式設計師幾乎總可以抽象得到不同的介面。

本文並不打算深入討論介面抽象的原則或建議,僅針對子系統或模組之間的介面抽象,介紹兩種典型的介面抽象結果,即函式介面與訊息介面,至於如何選取便由程式設計師根據產品特色而決定了。

在介紹兩種介面抽象結果之前,先大概介紹一種產品開發中最常見的樹狀軟體系統架構,如下圖所示。一般產品的軟體系統由多個子系統組成,每個子系統又由若干模組組成,部分模組可能需要進一步細分為多個子模組,因此模組或子模組是軟體系統的基礎架構成分。當然,軟體系統架構會因產品而異,下圖僅是一種最常見的軟體系統架構。本文論述中將模組作為最底層的開發單元,僅為闡述簡潔。

以下分別討論函式介面與訊息介面。

1、  函式介面

所謂函式介面是指模組之間通過函式進行互動,以完成特定功能及資訊傳遞。簡而言之,函式介面本身便是一種模組之間的直接函式呼叫,例如模組a在某功能中直接呼叫模組b的相應函式,以實現相關功能。如下**所示,tdm模組中函式tdm_setstm1()需要呼叫模組bsp中的函式bsp_setfpga()才可完成相關功能的設定,此時兩個模組之間便是通過函式介面來互動的。

void tdm_setstm1(…)

正常情況下,程式設計師並不喜歡自己模組中的函式被其它模組直接呼叫,儘管這樣更快捷點,但由於增加了耦合故而維護或優化起來極為痛苦。因此,一般情況下,模組對外提供統一介面,將相應內部函式進行封裝,而不同模組交則通過統一函式介面進行互動。例如,如果模組a需要實現多個功能,而每個功能需要呼叫模組b不同的函式,此時模組b只需要將待呼叫的函式封裝到乙個對外函式介面中,模組a直接呼叫該介面,而不同功能則可通過引數進行區分。至於對外函式介面的抽象,並不是本文重點,但封裝抽象後的函式介面內部如何根據不同功能進行驅動,則是後續表驅動文章中的內容了,不再贅述。

儘管函式介面的方式便於理解整個功能的呼叫鏈,是符合邏輯思維的抽象結果,而資訊傳遞主要借助形參完成,但當模組之間的互動非常頻繁是維護起來便是災難。例如,不同模組之間資訊互動最常見的方式,便是函式介面的形參中使用c指標以傳遞記憶體位址,但如果某指標既需要傳入又需要傳出的話,即僅變更其某些欄位的取值,那對該指標的使用便要十分小心,以免變更了錯誤的字段。在我的產品經歷中,便發生過類似的錯誤,即模組a呼叫模組b中的統一對外介面時傳入了靜態結構陣列的指標,但模組b對此是一無所知的,導致結構體中的乙個欄位會累加賦值,從而引入故障。更可悲的是,該故障在產品大規模商用的近兩年後才被偶然發現!

總而言之,函式介面最終呈現出來就是c/c++中最常見的函式呼叫,只不過呼叫者與被呼叫者分屬不同的模組而已。

2、  訊息介面

所謂訊息介面是指子系統或模組之間通過訊息進行互動,以完成特定功能及資訊傳遞。訊息介面不像函式介面那樣是一種身體力行的方式,其更關注訊息的互動流程。如下圖所示為一種常見的模組間訊息互動流程,模組a先傳送request訊息至模組b,模組b收到該訊息後進行相應處理,繼而傳送respond訊息給模組a,以反饋處理結果。

訊息介面本質上是一種訊號傳遞,而這種方式也是人類溝通的主要形式。例如,去麥當勞用餐時,顧客首先要告訴服務員所點食物,相當於顧客向麥當勞發出了request訊息;而服務員在下單後告知廚房準備食物,相當於麥當勞在處理request請求;當食物準備完成後再由服務員遞給故而,相當於麥當勞給顧客返回了respond響應。很多時候,僅傳遞訊號是不夠的,還需要傳遞相關的資訊,而訊息介面中的資訊傳遞一般通過記憶體段實現。例如,去麥當勞用餐時顧客不能僅告訴服務員「我要吃飯」,必須進一步告知其具體的食物名稱。

訊息分為同步訊息與非同步訊息兩種。同步訊息是指傳送方在訊息傳送至接收方後,必須等待對方的回應才可以處理後續事物,而在收到回應之前的等待時間內是不能處理其它事物的;非同步訊息是指傳送方在訊息傳送至接收方後,無需等待對方回應可轉而處理後續事物,而對方處理完訊息後再給傳送方回應即可。例如,顧客去麥當勞用餐,一般情況下點餐付款完成後,服務員在將所點食物遞給顧客後,才可以招待下一位顧客,而中間是不會被其它顧客打斷的,這便與同步訊息的處理類似。又例如,去中餐館吃飯時一般都是點餐後告知服務員,然後一直等待上菜,而服務員在完成選單下單後便去響應其他顧客了,並不會在旁邊一直等待菜品上桌,直到顧客用餐完後找服務員付款,這便與非同步訊息的處理類似。

嚴格地講,函式介面的處理流程本身便是同步的,即處理過程中不可能給其它事物打斷,甚至可將函式介面認為是同步訊息介面的特例;而訊息介面的處理流程則因訊息種類而異,同步訊息是不允許被其它事物打斷的,但非同步訊息天生便會轉而處理其它事物。一般軟體設計開發中,廣泛應用的是非同步訊息,但特殊情況下必須使用同步訊息。

無論函式介面還是訊息介面,均是軟體設計開發中廣泛使用的兩種介面形式,至於孰優孰劣根本無從定論。軟體設計需要考慮系統架構的層次關係、模組耦合、功能聚合等等,純粹地從介面形式判斷孰優孰劣是武斷的,必須結合模組具體功能及上下文模組關係而定。例如,最頂層的ui或管理軟體與下層模組互動時廣泛使用訊息介面,而同一子系統內部功能耦合嚴重的模組間可能更傾向於函式介面。至於選取何種介面,不是本文的論述重點,本文僅簡介兩種常見的抽象結果。

以上討論了兩種最常見的子系統或模組之間的介面抽象結果,僅為本人在產品開發中的一些經驗,可能存在侷限性,且謬誤之處在所難免,僅為進一步討論拋磚引玉。

產品開發這幾年(5)編碼規範

真正的程式設計師將 視為生命的結晶,從不浪費。然而,程式設計師並非天神,也會犯錯,所以沒有bug的 永遠不存在。為了打破宿命,程式設計師拼命修煉,似朝聖一般對 精益求精。由於程式設計師性格各異,各自修煉法訣千差萬別,單打獨鬥各有所長,但當共同面臨強大的武林公敵時,即便有高手壓陣,相互配合也顯得捉襟見...

產品開發這幾年(6)目錄結構

如無意外,產品開發中的目錄結構一定為採用樹狀結構,這幾乎是所有系統架構師的唯一選擇。可能本人有幾分孤陋寡聞,但我固執地以為諸如網狀結構 線性結構等目錄結構可能有用武之地,但絕對是不得已而為之。或許有幾分武斷,但卻不可否認的是,樹狀結構是最符合人類邏輯思維的組織結構。避開產品開發不談,上至國家的政治體...

TypeScript 基礎2 介面

介面通常以inte ce來宣告,介面是抽象方法的集合,即只宣告,不定義具體值。類描述物件的屬性和方法。介面則包含類要實現的方法 除非實現介面的類是抽象類,否則該類要定義介面中的所有方法 乙個實現介面的類,必須實現介面內所描述的所有方法,否則就必須宣告為抽象類。介面支援多繼承,乙個類可以實現多個介面 ...