魏禮俊
?
用戶二次開(kāi)發(fā)軟件的兼容性架構(gòu)設(shè)計(jì)
魏禮俊
針對(duì)企業(yè)生產(chǎn)實(shí)踐中經(jīng)常遇到的、用戶在設(shè)備供應(yīng)商提供的接口庫(kù)函數(shù)基礎(chǔ)上二次開(kāi)發(fā)的軟件,因供應(yīng)商接口庫(kù)函數(shù)版本升級(jí)帶來(lái)的軟件兼容性問(wèn)題,以C、C++語(yǔ)言接口庫(kù)函數(shù)為例,分析可以采取的軟件措施及其利弊,提出優(yōu)化的軟件架構(gòu)設(shè)計(jì)方法,防患于未然,力圖使用戶二次開(kāi)發(fā)軟件以最小的代碼修改量與維護(hù)復(fù)雜度,事半功倍,實(shí)現(xiàn)與供應(yīng)商提供的系列軟件接口庫(kù)函數(shù)全兼容,從而達(dá)到設(shè)備效能得以最大發(fā)揮且穩(wěn)定可靠運(yùn)行的最終目的。
軟件兼容性;軟件接口;架構(gòu)設(shè)計(jì)
在企業(yè)生產(chǎn)實(shí)踐中,經(jīng)常需在供應(yīng)商提供的軟件接口庫(kù)基礎(chǔ)上進(jìn)行二次開(kāi)發(fā),才能最大發(fā)揮相應(yīng)設(shè)備的功能。對(duì)于同類款式的系列設(shè)備,有時(shí)供應(yīng)商會(huì)對(duì)軟件接口庫(kù)進(jìn)行版本升級(jí),迫使在供應(yīng)商前款軟件基礎(chǔ)上進(jìn)行二次開(kāi)發(fā)的用戶軟件也需作同步更新,否則無(wú)法繼續(xù)使用。用戶軟件在開(kāi)發(fā)初始版本時(shí)該如何設(shè)計(jì)架構(gòu),便于應(yīng)對(duì)后續(xù)可能發(fā)生的供應(yīng)商軟件升級(jí)帶來(lái)的軟件兼容性問(wèn)題,實(shí)現(xiàn)用戶軟件修訂時(shí)代碼改動(dòng)量最少、維護(hù)最簡(jiǎn)便,從而運(yùn)行最可靠的最終目標(biāo),值得認(rèn)真考慮。
一般而言,供應(yīng)商軟件接口庫(kù)升級(jí)不會(huì)沒(méi)有章法,除新增功能接口函數(shù)外,原有功能接口函數(shù)大都僅改變函數(shù)名稱(防止新舊庫(kù)文件同時(shí)存在時(shí)的同名問(wèn)題可能引起用戶軟件無(wú)法編譯、運(yùn)行)。即使有個(gè)別函數(shù)發(fā)生了重大改變,也可視其為新增功能接口函數(shù)。下面將以C、C++語(yǔ)言接口庫(kù)函數(shù)為例,以偽代碼形式介紹解決用戶二次開(kāi)發(fā)軟件在兼容性方面需作的架構(gòu)考慮。
對(duì)于用戶二次開(kāi)發(fā)軟件來(lái)說(shuō),能正確定位、使用接口庫(kù)中相應(yīng)函數(shù)是第一要?jiǎng)?wù)。原有功能接口函數(shù)需重新定位、使用,而新增功能接口函數(shù)在二次開(kāi)發(fā)的軟件代碼中需作全新封裝處理。
總體來(lái)看,有3種基本方法處理接口庫(kù)函數(shù)升級(jí)問(wèn)題:使用預(yù)編譯項(xiàng)、使用配置文件或用戶界面選項(xiàng)、使用函數(shù)指針數(shù)組。前兩種方法比較直觀,都是使得程序按if-else選擇結(jié)構(gòu)進(jìn)行分支處理,但后續(xù)代碼維護(hù)量大;而使用函數(shù)指針數(shù)組的方法則比較含蓄,且后續(xù)代碼維護(hù)簡(jiǎn)易。以下將逐一解析上述3種處理方法處理各版本接口函數(shù)的過(guò)程,比較利弊,最后給出較為優(yōu)化的解決方法。
2.1 使用預(yù)編譯項(xiàng)
假設(shè)用戶二次開(kāi)發(fā)軟件針對(duì)供應(yīng)商接口庫(kù)某一接口函數(shù)的初始版本是:
RET_TYPE User_func_examp(……)
{
……
PARAM_A_TYPE parama;
API-_A_TYPE_func(parama);
……
}
供應(yīng)商接口庫(kù)函數(shù)版本升級(jí)后,用戶軟件采用類似如下的預(yù)編譯項(xiàng)進(jìn)行不同接口庫(kù)同一功能接口函數(shù)選擇:
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
……
}
用戶軟件中所有用到的供應(yīng)商接口庫(kù)接口函數(shù)都需作類似處理。處理完畢后,用戶還需在編譯器未編譯到上述代碼之前的合適位置顯式地定義當(dāng)前所使用的版本,例如:#define VERSION_B;或者是在編譯器編譯選項(xiàng)中添加適當(dāng)?shù)木幾g選項(xiàng),如-D VERSION_B。編譯后,重新運(yùn)行。
可以看出,不論是否有新增功能函數(shù),各版本所有功能接口函數(shù)都能進(jìn)行類似處理,但多個(gè)C、C++文件需逐一作同步更新,程序修改、維護(hù)都頗為繁瑣。
2.2 使用配置文件或用戶界面選項(xiàng)
同樣假設(shè)用戶二次開(kāi)發(fā)軟件針對(duì)供應(yīng)商接口庫(kù)某一接口函數(shù)的初始版本同上?,F(xiàn)在供應(yīng)商接口庫(kù)函數(shù)版本升級(jí)后,用戶軟件可在某個(gè)文件路徑下放置配置文件config.txt,文件內(nèi)容如下:
Version_Tye:
在該語(yǔ)句后可輸入如TYPE_A、TYPE_B、……、TYPE_X等版本信息,用戶軟件在讀入使用者填入的版本信息并判斷信息有效性后,轉(zhuǎn)入對(duì)應(yīng)供應(yīng)商接口庫(kù)函數(shù)運(yùn)行分支。用戶軟件也可在用戶界面中進(jìn)行版本信息讀取、處理、有效性判斷,同樣轉(zhuǎn)入對(duì)應(yīng)供應(yīng)商接口庫(kù)函數(shù)運(yùn)行分支。例如:
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:
出錯(cuò)記錄;
break;
}
……
}
編譯后,重新運(yùn)行。
如使用預(yù)編譯項(xiàng)類似,各版本所有功能接口函數(shù)都能進(jìn)行這樣的case處理;但增加過(guò)多的case使得函數(shù)路徑增加,程序維護(hù)難度加大。
2.3 使用函數(shù)指針數(shù)組
同樣假設(shè)用戶二次開(kāi)發(fā)軟件針對(duì)供應(yīng)商接口庫(kù)某一接口函數(shù)的初始版本同上;在供應(yīng)商接口庫(kù)函數(shù)版本升級(jí)后,該接口函數(shù)可能有如下兩種變化:
如果各版本僅改變了函數(shù)名稱,則可定義如下形式的接口函數(shù)跳轉(zhuǎn)表:
typedef RET_TYPE (*FP_Func[FUNC_NUM_MAX])(PARAM) = {API-_A_TYPE_func,
API-_B_TYPE_func,
……
API-_X_TYPE_func};
用戶二次開(kāi)發(fā)軟件接口函數(shù)按如下方式使用該跳轉(zhuǎn)表:
RET_TYPE User_func_examp(……)
{
……
FP_Func fun_handle;
(*FP_Func[Version_Type])(PARAM);
……
}
上述示意代碼中的Version_Type可來(lái)自于配置文件或用戶界面選項(xiàng)。編譯后,重新運(yùn)行。
如果各版本相互差異較大,如參數(shù)列表或返回參數(shù)類型已完全改變,則可以使用前述預(yù)編譯項(xiàng)、配置文件或用戶界面選項(xiàng)方法加以解決;或者按上述接口函數(shù)跳轉(zhuǎn)表思路進(jìn)行全新的二次開(kāi)發(fā)。
可以看出,對(duì)于各版本大部分功能接口函數(shù)來(lái)說(shuō),適用函數(shù)指針數(shù)組的方法,代碼維護(hù)量大為降低,僅需維護(hù)各個(gè)接口函數(shù)跳轉(zhuǎn)表。但對(duì)于每個(gè)用戶接口函數(shù),都需要有類似User_func_examp的處理過(guò)程,因此,仍有必要繼續(xù)優(yōu)化代碼架構(gòu)。
從使用者習(xí)慣來(lái)看,一般先選擇,正確設(shè)置某一類型參數(shù)后,即可以開(kāi)始運(yùn)行特定功能函數(shù)。為此,需要斟酌選用現(xiàn)有軟件方法加以合理使用。二次軟件開(kāi)發(fā)可作如下優(yōu)化處理過(guò)程:
對(duì)供應(yīng)商提供的接口庫(kù)函數(shù)進(jìn)行全面梳理,將版本雖不同,但接口函數(shù)的參數(shù)列表、返回參數(shù)中有某幾項(xiàng)類型對(duì)應(yīng)相同的集中在一起視作某一類型函數(shù)。例如:若干個(gè)無(wú)參、返回參數(shù)類型相同的接口函數(shù);若干個(gè)輸入?yún)?shù)、返回參數(shù)類型相同,無(wú)其余參數(shù)的接口函數(shù);若干個(gè)輸出參數(shù)、返回參數(shù)類型相同,無(wú)其余參數(shù)的接口函數(shù)等;
單列出各版本相互差異較大的個(gè)別接口函數(shù);
經(jīng)過(guò)梳理后,對(duì)于可以歸并為某幾個(gè)類型的函數(shù),分別用如下的二維函數(shù)指針數(shù)組進(jìn)行定義:
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}};
對(duì)應(yīng)二維函數(shù)指針數(shù)組的接口函數(shù)跳轉(zhuǎn)表,可以采用與前述類似的處理過(guò)程:
RET_TYPE User_func_examp(……)
{
……
FP_Func2 fun_handle;
(*FP_Func2[Version_Type][Func_Number])(PARAM);
……
}
Version_Type、Func_Number來(lái)自用戶軟件界面或者配置文件。此時(shí),Version_Type(枚舉值數(shù)目不超過(guò)VERS_NUM_MAX)、Func_Number(枚舉值數(shù)目不超過(guò)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;
而對(duì)于那些不能集中的個(gè)別接口函數(shù),則仍然使用前述的預(yù)編譯項(xiàng)、配置文件或用戶界面選項(xiàng)方法加以解決;或者按上述接口函數(shù)跳轉(zhuǎn)表思路進(jìn)行全新的二次開(kāi)發(fā)。
而為了便于維護(hù),所有的函數(shù)指針數(shù)組可以放在同一個(gè).h頭文件中。如此處理后,有望從設(shè)計(jì)層面將版本升級(jí)帶來(lái)的修訂、維護(hù)成本大幅降低,即已有接口函數(shù)可以繼續(xù)運(yùn)行,只需擴(kuò)充新增類似功能的接口函數(shù)。
良好的軟件架構(gòu)設(shè)計(jì)將為后續(xù)軟件編碼、維護(hù)帶來(lái)極大便利,這是共識(shí)。但在實(shí)際工程中,這一點(diǎn)卻又經(jīng)常被有意無(wú)意地忽視?,F(xiàn)在忽視架構(gòu)設(shè)計(jì),僅僅停留在程序可以運(yùn)行,代碼一蹴而就,那只會(huì)為將來(lái)事倍功半的程序維護(hù)買單,而且也不利于代碼質(zhì)量的提高。本文試圖以管窺豹,探討一下用戶二次開(kāi)發(fā)軟件架構(gòu)優(yōu)化設(shè)計(jì)帶來(lái)的程序簡(jiǎn)潔、健壯、易維護(hù)性方面的好處,以期更好地服務(wù)于實(shí)際工程。
[1] Prata S.著,云巔工作室 譯,C Primer Plus 中文版[第五版] [M],北京:人民郵電出版社,2005
[2] Stephen Prata著,孫建春、韋強(qiáng)譯,C++ Primer Plus 中文版[第五版],[M]北京:人民郵電出版社,2005
[3] 錢能著,C++ 程序設(shè)計(jì)教程[第二版][M],北京:清華大學(xué)出版社,2005
[4] 凌堅(jiān)、隋成華,基于組件結(jié)構(gòu)的軟件二次開(kāi)發(fā)接口的設(shè)計(jì)與實(shí)現(xiàn)[J],計(jì)算機(jī)工程, 28(2),2002年2月
[5] 李江紅、韓正之,Matlab和C++接口中函數(shù)注冊(cè)的實(shí)現(xiàn)[J],計(jì)算機(jī)應(yīng)用,2000年4月第20期
[6] 朱傳安、潘大夫,Matlab與C/C++混合編程接口及應(yīng)用[J],微計(jì)算機(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-),男,安徽省當(dāng)涂縣,上海微電子裝備有限公司,分系統(tǒng)與整機(jī)軟件開(kāi)發(fā),工程師,工學(xué)碩士,研究方向:應(yīng)用軟件開(kāi)發(fā)、算法仿真分析、圖像處理算法編程等,上海,201203