魏禮俊
?
用戶二次開發軟件的兼容性架構設計
魏禮俊
針對企業生產實踐中經常遇到的、用戶在設備供應商提供的接口庫函數基礎上二次開發的軟件,因供應商接口庫函數版本升級帶來的軟件兼容性問題,以C、C++語言接口庫函數為例,分析可以采取的軟件措施及其利弊,提出優化的軟件架構設計方法,防患于未然,力圖使用戶二次開發軟件以最小的代碼修改量與維護復雜度,事半功倍,實現與供應商提供的系列軟件接口庫函數全兼容,從而達到設備效能得以最大發揮且穩定可靠運行的最終目的。
軟件兼容性;軟件接口;架構設計
在企業生產實踐中,經常需在供應商提供的軟件接口庫基礎上進行二次開發,才能最大發揮相應設備的功能。對于同類款式的系列設備,有時供應商會對軟件接口庫進行版本升級,迫使在供應商前款軟件基礎上進行二次開發的用戶軟件也需作同步更新,否則無法繼續使用。用戶軟件在開發初始版本時該如何設計架構,便于應對后續可能發生的供應商軟件升級帶來的軟件兼容性問題,實現用戶軟件修訂時代碼改動量最少、維護最簡便,從而運行最可靠的最終目標,值得認真考慮。
一般而言,供應商軟件接口庫升級不會沒有章法,除新增功能接口函數外,原有功能接口函數大都僅改變函數名稱(防止新舊庫文件同時存在時的同名問題可能引起用戶軟件無法編譯、運行)。即使有個別函數發生了重大改變,也可視其為新增功能接口函數。下面將以C、C++語言接口庫函數為例,以偽代碼形式介紹解決用戶二次開發軟件在兼容性方面需作的架構考慮。
對于用戶二次開發軟件來說,能正確定位、使用接口庫中相應函數是第一要務。原有功能接口函數需重新定位、使用,而新增功能接口函數在二次開發的軟件代碼中需作全新封裝處理。
總體來看,有3種基本方法處理接口庫函數升級問題:使用預編譯項、使用配置文件或用戶界面選項、使用函數指針數組。前兩種方法比較直觀,都是使得程序按if-else選擇結構進行分支處理,但后續代碼維護量大;而使用函數指針數組的方法則比較含蓄,且后續代碼維護簡易。以下將逐一解析上述3種處理方法處理各版本接口函數的過程,比較利弊,最后給出較為優化的解決方法。
2.1 使用預編譯項
假設用戶二次開發軟件針對供應商接口庫某一接口函數的初始版本是:
RET_TYPE User_func_examp(……)
{
……
PARAM_A_TYPE parama;
API-_A_TYPE_func(parama);
……
}
供應商接口庫函數版本升級后,用戶軟件采用類似如下的預編譯項進行不同接口庫同一功能接口函數選擇:
RET_TYPE User_func_examp(……)
{
……
#ifdef VersionA
PARAM_A_TYPE parama;
API-_A_TYPE_func(parama);
#elif VersionB
PARAM_B_TYPE paramb;
API-_B_TYPE_func(paramb);
……
#else
PARAM_X_TYPE paramx;
API-_X_TYPE_func(paramx);
#endif
……
}
用戶軟件中所有用到的供應商接口庫接口函數都需作類似處理。處理完畢后,用戶還需在編譯器未編譯到上述代碼之前的合適位置顯式地定義當前所使用的版本,例如:#define VERSION_B;或者是在編譯器編譯選項中添加適當的編譯選項,如-D VERSION_B。編譯后,重新運行。
可以看出,不論是否有新增功能函數,各版本所有功能接口函數都能進行類似處理,但多個C、C++文件需逐一作同步更新,程序修改、維護都頗為繁瑣。
2.2 使用配置文件或用戶界面選項
同樣假設用戶二次開發軟件針對供應商接口庫某一接口函數的初始版本同上?,F在供應商接口庫函數版本升級后,用戶軟件可在某個文件路徑下放置配置文件config.txt,文件內容如下:
Version_Tye:
在該語句后可輸入如TYPE_A、TYPE_B、……、TYPE_X等版本信息,用戶軟件在讀入使用者填入的版本信息并判斷信息有效性后,轉入對應供應商接口庫函數運行分支。用戶軟件也可在用戶界面中進行版本信息讀取、處理、有效性判斷,同樣轉入對應供應商接口庫函數運行分支。例如:
RET_TYPE User_func_examp(……)
{
……
switch(Version_Type)
{
case TYPE_A:
PARAM_A_TYPE parama;
API-_A_TYPE_func(parama);
break;
case TYPE_B:
PARAM_B_TYPE paramb;
API-_B_TYPE_func(paramb);
break;
……
case TYPE_X:
PARAM_X_TYPE paramx;
API-_X_TYPE_func(paramx);
beak;
default:
出錯記錄;
break;
}
……
}
編譯后,重新運行。
如使用預編譯項類似,各版本所有功能接口函數都能進行這樣的case處理;但增加過多的case使得函數路徑增加,程序維護難度加大。
2.3 使用函數指針數組
同樣假設用戶二次開發軟件針對供應商接口庫某一接口函數的初始版本同上;在供應商接口庫函數版本升級后,該接口函數可能有如下兩種變化:
如果各版本僅改變了函數名稱,則可定義如下形式的接口函數跳轉表:
typedef RET_TYPE (*FP_Func[FUNC_NUM_MAX])(PARAM) = {API-_A_TYPE_func,
API-_B_TYPE_func,
……
API-_X_TYPE_func};
用戶二次開發軟件接口函數按如下方式使用該跳轉表:
RET_TYPE User_func_examp(……)
{
……
FP_Func fun_handle;
(*FP_Func[Version_Type])(PARAM);
……
}
上述示意代碼中的Version_Type可來自于配置文件或用戶界面選項。編譯后,重新運行。
如果各版本相互差異較大,如參數列表或返回參數類型已完全改變,則可以使用前述預編譯項、配置文件或用戶界面選項方法加以解決;或者按上述接口函數跳轉表思路進行全新的二次開發。
可以看出,對于各版本大部分功能接口函數來說,適用函數指針數組的方法,代碼維護量大為降低,僅需維護各個接口函數跳轉表。但對于每個用戶接口函數,都需要有類似User_func_examp的處理過程,因此,仍有必要繼續優化代碼架構。
從使用者習慣來看,一般先選擇,正確設置某一類型參數后,即可以開始運行特定功能函數。為此,需要斟酌選用現有軟件方法加以合理使用。二次軟件開發可作如下優化處理過程:
對供應商提供的接口庫函數進行全面梳理,將版本雖不同,但接口函數的參數列表、返回參數中有某幾項類型對應相同的集中在一起視作某一類型函數。例如:若干個無參、返回參數類型相同的接口函數;若干個輸入參數、返回參數類型相同,無其余參數的接口函數;若干個輸出參數、返回參數類型相同,無其余參數的接口函數等;
單列出各版本相互差異較大的個別接口函數;
經過梳理后,對于可以歸并為某幾個類型的函數,分別用如下的二維函數指針數組進行定義:
typedef RET_TYPE (*FP_Fun2c[VERS_NUM_MAX][FUNC_NUM_MAX])(PARAM) =
{{TYPE_A, A_FUNC_NBR1},
{TYPE_A, A_FUNC_NBR2},
……
{TYPE_A, A_FUNC_NBRN},
{TYPE_B, B_FUNC_NBR1},
{TYPE_B, B_FUNC_NBR2},
……
{TYPE_B, B_FUNC_NBRN},
……
{TYPE_X, X_FUNC_NBR1},
{TYPE_X, X_FUNC_NBR2},
……
{TYPE_X, X_FUNC_NBRN}};
對應二維函數指針數組的接口函數跳轉表,可以采用與前述類似的處理過程:
RET_TYPE User_func_examp(……)
{
……
FP_Func2 fun_handle;
(*FP_Func2[Version_Type][Func_Number])(PARAM);
……
}
Version_Type、Func_Number來自用戶軟件界面或者配置文件。此時,Version_Type(枚舉值數目不超過VERS_NUM_MAX)、Func_Number(枚舉值數目不超過FUNC_NUM_MAX)可作如下枚舉定義:
Typedef enum
{
TYPE_A,
TYPE_B,
……
TYPE_X
} VERSION_TYPE_ENUM;
Typedef enum
{
FUNC_NBR1,
FUNC_NBR2,
……
FUNC_NBRN
} FUNC_NBR_ENUM;
而對于那些不能集中的個別接口函數,則仍然使用前述的預編譯項、配置文件或用戶界面選項方法加以解決;或者按上述接口函數跳轉表思路進行全新的二次開發。
而為了便于維護,所有的函數指針數組可以放在同一個.h頭文件中。如此處理后,有望從設計層面將版本升級帶來的修訂、維護成本大幅降低,即已有接口函數可以繼續運行,只需擴充新增類似功能的接口函數。
良好的軟件架構設計將為后續軟件編碼、維護帶來極大便利,這是共識。但在實際工程中,這一點卻又經常被有意無意地忽視。現在忽視架構設計,僅僅停留在程序可以運行,代碼一蹴而就,那只會為將來事倍功半的程序維護買單,而且也不利于代碼質量的提高。本文試圖以管窺豹,探討一下用戶二次開發軟件架構優化設計帶來的程序簡潔、健壯、易維護性方面的好處,以期更好地服務于實際工程。
[1] Prata S.著,云巔工作室 譯,C Primer Plus 中文版[第五版] [M],北京:人民郵電出版社,2005
[2] Stephen Prata著,孫建春、韋強譯,C++ Primer Plus 中文版[第五版],[M]北京:人民郵電出版社,2005
[3] 錢能著,C++ 程序設計教程[第二版][M],北京:清華大學出版社,2005
[4] 凌堅、隋成華,基于組件結構的軟件二次開發接口的設計與實現[J],計算機工程, 28(2),2002年2月
[5] 李江紅、韓正之,Matlab和C++接口中函數注冊的實現[J],計算機應用,2000年4月第20期
[6] 朱傳安、潘大夫,Matlab與C/C++混合編程接口及應用[J],微計算機信息(管控一體化),2010年第26卷第5-3期
Design of Compatible Framework in Software Further Development of Users
Wei Lijun
(SMEE, Shanghai 201203, China)
This paper aims at the software compatible problems caused by version upgrade of the interface library functions provided by the providers. It is often come up in the production practice when the users do the further development of their software on the basis of these interface library functions. While taking the application software interfaces written in C/C++ language as an example, this paper analyzes the software measures and their advantages and disadvantages. Then it puts forward the optimized framework design method, trying to nip in the bud to provide the user’s software further development with minimum modification of codes and least complication degree of maintenance. It realizes the comprehensive compatibility with the interface library functions of the serial software provided by the providers to obtain the final target of stable and reliable running of the equipments and their maximum efficiency.
Compatibility of Software; Software Interface; Framework Design
1007-757X(2016)04-0048-03
TP391.41
A
(2015.08.17)
魏禮俊(1976-),男,安徽省當涂縣,上海微電子裝備有限公司,分系統與整機軟件開發,工程師,工學碩士,研究方向:應用軟件開發、算法仿真分析、圖像處理算法編程等,上海,201203