穆澤慧,雷聚超,胡靜宜,王亞銘,趙雅霖
(西安工業(yè)大學(xué) 計(jì)算機(jī)科學(xué)與工程學(xué)院,西安 710021)
隨著信息時(shí)代的到來(lái),人們對(duì)軟件的需求越來(lái)越大。市場(chǎng)上一般使用C#、Delphi、Java、PHP等工具進(jìn)行軟件開發(fā)[1],在使用這類軟件進(jìn)行開發(fā)時(shí),需要很長(zhǎng)的周期來(lái)完成對(duì)應(yīng)的功能需求,同時(shí)會(huì)出現(xiàn)大量的代碼重復(fù)問(wèn)題,尤其是在信息化管理系統(tǒng)(ERP系統(tǒng))中有很多類似的業(yè)務(wù)邏輯,在每個(gè)模塊中都需要對(duì)數(shù)據(jù)進(jìn)行最基本的如增加、修改、刪除和取消等操作[2-3]。目前,市場(chǎng)上的軟件均為B/S[4]、C/S[5]結(jié)構(gòu),使用Java、C等語(yǔ)言開發(fā)B/S和C/S結(jié)構(gòu)時(shí),連接數(shù)據(jù)庫(kù)或服務(wù)器的工作比較繁瑣。近年來(lái),隨著DataSnap技術(shù)[6]的出現(xiàn),Delphi 將其集成在功能平臺(tái)之中,為多層軟件(C/SS)[7]的開發(fā)提供了極大的便利。Delphi在使用DataSnap技術(shù)構(gòu)建三層服務(wù)器時(shí)提供了一套FireDAC技術(shù)[8]的組件,該組件可以通過(guò)相關(guān)的設(shè)置搭建服務(wù)器[9-10],同時(shí)在客戶端中引入服務(wù)器連接組件并進(jìn)行設(shè)置,可直接連接到服務(wù)器。
為解決上述問(wèn)題,本文擬在Delphi中通過(guò)設(shè)計(jì)自定義組件來(lái)達(dá)到軟件快速開發(fā)的目的,用DataSnap技術(shù)構(gòu)建三層架構(gòu)[1],實(shí)現(xiàn)廣域網(wǎng)的C/S應(yīng)用,同時(shí)提高編程人員的效率,減少代碼重復(fù)率。
在系統(tǒng)開發(fā)過(guò)程中可以根據(jù)需求分析整理出相應(yīng)的邏輯功能,而這其中有部分邏輯功能是重復(fù)的,這導(dǎo)致在軟件設(shè)計(jì)過(guò)程中需要進(jìn)行很多重復(fù)性的工作。若能將這些重復(fù)的工作放在一個(gè)組件中,通過(guò)相關(guān)屬性設(shè)置來(lái)完成其對(duì)應(yīng)功能,就可極大減少代碼的重復(fù)率,提高編程人員的開發(fā)速度,自定義組件由此應(yīng)運(yùn)而生。
Delphi組件是一個(gè)對(duì)象庫(kù),也是一個(gè)類。在Delphi中所有對(duì)象的基類都是TObject,組件的最基類也是TObject,其結(jié)構(gòu)如圖1所示。
圖1 Delphi的類結(jié)構(gòu)Fig.1 Class structure of Delphi
該結(jié)構(gòu)中組件的類層次為:TObject→TPersistent→TComponent→TControl。
TComponent是所有Delphi組件的基類,所有要注冊(cè)到IDE直接進(jìn)行可視化的對(duì)象庫(kù)均要從這個(gè)類繼承,TComponent提供了必不可少的信息以使組件能在Delphi的IDE上運(yùn)作。TComponent 衍生出的TControl的類是所有可視化控件的基類,開發(fā)出的組件都基于TComponent。當(dāng)創(chuàng)建一個(gè)新的組件時(shí),通過(guò)該層次關(guān)系可從已存在的一個(gè)類的類型中派生出新的類,添加到組件的庫(kù)中。
在Delphi中開發(fā)自定義組件時(shí),創(chuàng)建一個(gè)新組件(New Component)需要選擇組件父類的類型,生成對(duì)應(yīng)的.pas文檔,在文檔中添加組件特有的屬性、方法和事件以完成它的相關(guān)功能;對(duì)其文檔進(jìn)行編譯和安裝;在面板庫(kù)中找到新安裝的組件進(jìn)行業(yè)務(wù)和功能性測(cè)試以滿足功能要求。該過(guò)程必須完成以下的步驟:① 為新的組件創(chuàng)建單元,如:unit1.pas;② 從已有組件類型中派生組件,即繼承已存在的組件的類型,如TButton、TDBEditEh等;③ 為新的組件添加特有屬性、方法和事件完成其獨(dú)特的功能;④ 向IDE注冊(cè)組件;⑤ 為組件創(chuàng)建位圖;⑥ 創(chuàng)建包并在IDE中安裝組件;⑦ 為組件與其屬性、方法和事件創(chuàng)建幫助文檔。
創(chuàng)建新組件一般選擇已存在的組件對(duì)其進(jìn)行二次開發(fā),并修改或增加組件的屬性、方法和事件[11]。屬性是組件中明顯的部分,應(yīng)用程序開發(fā)人員可以在設(shè)計(jì)時(shí)看到并對(duì)其進(jìn)行操作。同時(shí),組件在窗體設(shè)計(jì)器中發(fā)生反應(yīng),立即會(huì)得到反饋。設(shè)計(jì)良好的屬性會(huì)使組件易被其他開發(fā)人員使用及維護(hù)。事件是把所發(fā)生的事情鏈接到一些代碼的機(jī)制。組件的方法是內(nèi)置于類結(jié)構(gòu)中的過(guò)程和函數(shù),需要遵循的標(biāo)準(zhǔn)為:消除依賴、命名方法、保護(hù)方法及聲明方法等。
快速開發(fā)模式通過(guò)開發(fā)模板組件即自定義組件來(lái)實(shí)現(xiàn)軟件系統(tǒng)的快速開發(fā)[12]。開發(fā)模板由數(shù)據(jù)操作模塊與數(shù)據(jù)傳輸模塊組成,快速開發(fā)模型的結(jié)構(gòu)如圖2所示。
圖2 快速開發(fā)模型Fig.2 Rapid development model
其原理是從模板組件的屬性中獲取到當(dāng)前的表名之后,連接服務(wù)器組件來(lái)獲取數(shù)據(jù)庫(kù)中表的數(shù)據(jù),同時(shí)由初始化組件獲取當(dāng)前屏幕的分辨率從而計(jì)算出TDBGrid、TGroupBox、功能性組件的位置,最終實(shí)現(xiàn)窗體分辨率自適應(yīng)效果。其中TGroupBox中放置數(shù)據(jù)感應(yīng)編輯框,編輯框與TDBGrid、數(shù)據(jù)庫(kù)對(duì)應(yīng)的字段進(jìn)行關(guān)聯(lián),實(shí)現(xiàn)實(shí)時(shí)更新。
數(shù)據(jù)操作模塊以Delphi的組件開發(fā)技術(shù)為基礎(chǔ),引入“公有”這一概念,對(duì)系統(tǒng)所需的數(shù)據(jù)表操作并進(jìn)行歸納,將使用頻率高的操作通過(guò)組件開發(fā)的方式直接編寫,如:特定可視化組件中TButton和TDBEdit等,形成公有自定義組件。公有組件成為承載特定功能的開發(fā)元素。每個(gè)自定義組件都包含以下一種或幾種過(guò)程:
1) 建立包含新部件的庫(kù)單元;
2) 有部件類型中繼承得到新的部件類型;
3) 增加屬性、方法和事件;
4) 用Delphi注冊(cè)部件;
5) 為部件的屬性方法和事件建立Help文件。
在一個(gè)頁(yè)面中有很多自定義組件,如果要獲取當(dāng)前的程序流程信息、主表信息、操作人信息和從表信息等,需要設(shè)計(jì)一個(gè)自定義模板組件放置在每一個(gè)頁(yè)面中,模板組件的屬性設(shè)計(jì)見表1。
表1 模板屬性
接口組件中包含了數(shù)據(jù)表中對(duì)數(shù)據(jù)進(jìn)行操作識(shí)別的各個(gè)字段,并將其作為參數(shù)。開發(fā)過(guò)程中通過(guò)接口組件對(duì)各個(gè)字段進(jìn)行賦值,模板內(nèi)的其他組件通過(guò)取接口組件的各屬性值來(lái)獲得相應(yīng)的字段值。在創(chuàng)建模板組件時(shí),通過(guò)修改已有TButton組件添加屬于模板組件特有屬性和方法。在創(chuàng)建模板的組件時(shí),一定要添加聲明。模板組件的核心代碼為:
TMB = class(TButton)//聲明模板組件
Smb_mb_name:string;//模板組件名稱
Smb_mb_tablename:string;//當(dāng)前表名
Smb_pmb_tablename:string;//當(dāng)前編號(hào)
Procedure Fmb_mb_tablename(const Value:string);//添加模板方法,獲取屬性值
procedure Fmb_czr(const Value:string);
constructor Create(Aowner:TComponent);override;//創(chuàng)建模板組件
property mb_lcmc:string read Fmb_lcmc write Setmb_lcmc;//添加模板事件完成其功能
procedure Register;//模板組件的注冊(cè)
RegisterComponents('SJ',[TMB]);//將模板組件SJMB放在SJ文件下
constructor TSJMB.Create(Aowner:TComponent);//模板組件的初始化即形狀、名稱、字體等詳細(xì)需求
inherited Create(Aowner);{執(zhí)行繼承的其父類初始化過(guò)程 }
self.Text :='模板';
self.Font.Family :='宋體';
self.Font.Size:=11;
…
2.3.1 數(shù)據(jù)的獲取
一般設(shè)計(jì)功能性的自定義組件,需要獲取數(shù)據(jù)或輸出數(shù)據(jù)。在每一個(gè)頁(yè)面上有很多數(shù)據(jù)型組件,可以通過(guò)設(shè)計(jì)組件的命名規(guī)則找到對(duì)應(yīng)的數(shù)據(jù)型組件。如:在設(shè)置組件中制定統(tǒng)一的命名規(guī)則,如text_XXXX,其中XXXX為數(shù)據(jù)庫(kù)表中的字段名,text為字段的類型,根據(jù)text找到所需要的組件,根據(jù)XXXX將組件與數(shù)據(jù)庫(kù)中字段對(duì)應(yīng)。
2.3.2 數(shù)據(jù)的傳遞
使用JSON進(jìn)行數(shù)據(jù)傳遞。JSON是一種輕量級(jí)的數(shù)據(jù)交換格式,基于ECMAScript的一個(gè)子集,采用完全獨(dú)立于編程語(yǔ)言的文本格式來(lái)存儲(chǔ)和表示數(shù)據(jù)。JSON中有兩種結(jié)構(gòu):對(duì)象和數(shù)組。JSON的值由數(shù)字、字符串、邏輯值、數(shù)組、對(duì)象和null等組成。使用JSON作為客戶端與服務(wù)器之間的數(shù)據(jù)交換格式,JSON數(shù)據(jù)格式可以直接為服務(wù)器使用,大大簡(jiǎn)化了客戶端與服務(wù)器的代碼開發(fā)量,更易于維護(hù)。而且數(shù)據(jù)格式比較簡(jiǎn)單,易于讀寫,且格式均為壓縮的,占用帶寬小。
2.3.3 功能性組件之間互斥事件
當(dāng)按鈕的OnClick被執(zhí)行后,為了避免數(shù)據(jù)的混亂,必須使不相關(guān)的按鈕處于無(wú)效的狀態(tài)。例如,在信息化管理系統(tǒng)中當(dāng)點(diǎn)擊添加按鈕的時(shí)候,修改、刪除、歸檔、數(shù)據(jù)導(dǎo)出和返回等按鈕必須處于無(wú)效狀態(tài),而保存和取消按鈕則必須處于有效狀態(tài)。當(dāng)保存或取消按鈕被點(diǎn)擊后,增加、修改、歸檔和返回等按鈕應(yīng)該處于有效狀態(tài),而保存和取消按鈕應(yīng)該處于無(wú)效狀態(tài)。因此,必須在組件的OnClick事件中找到窗體中的相關(guān)組件進(jìn)行互斥性操作設(shè)置。
在基于DataSnap的三層信息化管理系統(tǒng)中,每一個(gè)窗體Form都是由很多組件構(gòu)成的。在窗體Form中實(shí)現(xiàn)其功能的步驟為:① 添加連接DataSnap服務(wù)器的組件;② 將TDBGrid組件和數(shù)據(jù)感應(yīng)組件添加到Form中,通過(guò)數(shù)據(jù)關(guān)聯(lián)組件如TDataSource將服務(wù)器中的數(shù)據(jù)用TDBGrid進(jìn)行顯示;③ 將TGroupBox組件的數(shù)據(jù)編輯框與TDBGrid組件相關(guān)聯(lián),并進(jìn)行實(shí)時(shí)顯示;④ 添加窗體Form所需要的功能性組件,其中功能性組件包括必須的和非必須的,必須的組件包含模板組件和初始化組件,非必須的組件包含添加組件、刪除組件、審核組件和歸檔組件等。其頁(yè)面的整體結(jié)構(gòu)層次如圖3所示。對(duì)于圖3中功能性組件之間的關(guān)聯(lián),以增加組件和保存組件為例。
① 單擊增加組件后,其本身將處于無(wú)效狀態(tài),頁(yè)面上除取消組件、保存組件和編輯框處于有效狀態(tài)外,其他組件均處于無(wú)效狀態(tài)。若單擊增加組件后,頁(yè)面上所有組件都處于有效狀態(tài),則單擊TDBGrid組件、修改組件和刪除組件等會(huì)出現(xiàn)數(shù)據(jù)混亂現(xiàn)象。若沒(méi)有成功添加數(shù)據(jù)便執(zhí)行刪除操作,則會(huì)導(dǎo)致軟件崩潰以致于損壞電腦主機(jī)。使取消組件、保存組件和編輯框處于有效狀態(tài)是因?yàn)樵黾拥倪^(guò)程是從編譯框中讀取信息,保存組件可以將之前添加的數(shù)據(jù)信息保存到數(shù)據(jù)庫(kù)中,取消組件可以取消之前的添加操作。其結(jié)構(gòu)如圖4所示。
② 單擊保存組件后,其本身處于無(wú)效狀態(tài),頁(yè)面上除取消組件、保存組件和編輯框處于有無(wú)效狀態(tài)外,其他組件均處于有效狀態(tài)。若單擊保存組件后,頁(yè)面上所有組件都處于有效狀態(tài),則單擊取消組件、保存組件和編輯框組件將會(huì)使數(shù)據(jù)再次保存病修改,將會(huì)出現(xiàn)數(shù)據(jù)混亂不真實(shí)甚至導(dǎo)致軟件崩潰以致于損壞電腦主機(jī)的現(xiàn)象。使TDBGrid組件、修改組件、刪除組件、上傳組件和審核組件均處于有效狀態(tài)是因?yàn)閷?shù)據(jù)成功保存到數(shù)據(jù)庫(kù)中后,可以重新對(duì)數(shù)據(jù)庫(kù)表中的數(shù)據(jù)進(jìn)行操作,不會(huì)出現(xiàn)數(shù)據(jù)混亂等狀況。其結(jié)構(gòu)如圖5所示。
圖3 窗體結(jié)構(gòu)Fig.3 Form structure
圖4 增加組件結(jié)構(gòu)Fig.4 Structure of the additional components
圖5 保存組件結(jié)構(gòu)Fig.5 Structure of the saved components
1) 在Delphi中創(chuàng)建信息化管理項(xiàng)目。在項(xiàng)目開始之前將自定義組件的包地址引入到項(xiàng)目中,可以在項(xiàng)目設(shè)計(jì)的任何一個(gè)頁(yè)面工具箱中使用自定義組件。
2) 在Delphi的工具箱中的自定義組件包中可以看到常用的自定義組件,見表2。
表2 已完成的自定義組件
3)在頁(yè)面中添加需要的組件:連接服務(wù)器組件、功能必要組件(模板組件和初始化組件)和其他功能性組件。在模板組件中添加當(dāng)前頁(yè)面的信息,成功連接數(shù)據(jù)庫(kù)組件與數(shù)據(jù)顯示如圖6(a)所示,數(shù)據(jù)的顯示包含了TDBGrid、TDBEdit等數(shù)據(jù)組件,同時(shí)使用TBindSource組件進(jìn)行數(shù)據(jù)直接關(guān)聯(lián),即數(shù)據(jù)組件進(jìn)行連接,編譯框與數(shù)據(jù)庫(kù)中對(duì)應(yīng)的字段進(jìn)行關(guān)聯(lián),其結(jié)果如圖6(b)所示。
在項(xiàng)目開發(fā)過(guò)程中使用自定義組件開發(fā)方法,只需在頁(yè)面上添加所需的功能性組件,并對(duì)組件的屬性進(jìn)行設(shè)置,而不需要在OnClick事件中寫入任何代碼即可完成相關(guān)功能。在“供電所標(biāo)準(zhǔn)化作業(yè)流程”系統(tǒng)中使用傳統(tǒng)開發(fā)方法,387個(gè)頁(yè)面需要200個(gè)工作日完成開發(fā)調(diào)試工作,而在“縣級(jí)標(biāo)準(zhǔn)化管理流程”系統(tǒng)中使用本文所述的自定義組件方法開發(fā),673個(gè)頁(yè)面共用28個(gè)工作日完成,開發(fā)效率提高了80%以上。使用自定義組件開發(fā)方法的主要工作是開發(fā)組件,組件開發(fā)完成后,便可通過(guò)對(duì)組件屬性進(jìn)行設(shè)置來(lái)完成開發(fā)工作。因此,傳統(tǒng)開發(fā)方法需要2 d完成的窗體,自定義組件開發(fā)方法只需要40 min便可完成。而當(dāng)軟件需要升級(jí)修改時(shí),只需修改自定義組件代碼。這就極大減少了程序的Bug,提高了程序的運(yùn)行質(zhì)量。
圖7為信息化建設(shè)項(xiàng)目中的窗體效果。開發(fā)時(shí)僅需將相應(yīng)組件添加到窗體中并對(duì)屬性進(jìn)行設(shè)置即可實(shí)現(xiàn)相應(yīng)的功能,達(dá)到軟件快速開發(fā)的目的。
圖6 頁(yè)面上數(shù)據(jù)與對(duì)應(yīng)的數(shù)據(jù)組件關(guān)聯(lián)Fig.6 Association of data on the page with the corresponding data components
圖7 窗體效果Fig.7 Effect of form
文中在Delphi中利用組件的自定義方法,通過(guò)對(duì)組件父類的繼承并將組件的功能代碼放入組件的相應(yīng)事件中,通過(guò)對(duì)窗體組件的相關(guān)參數(shù)進(jìn)行設(shè)置,設(shè)計(jì)開發(fā)出滿足需求的相關(guān)功能性組件。實(shí)驗(yàn)結(jié)果表明,文中提出的自定義組件開發(fā)方法可提高開發(fā)效率、減少代碼重復(fù)率,為軟件高效運(yùn)行以及程序的更新、升級(jí)提供便利。從已經(jīng)開發(fā)完成的項(xiàng)目來(lái)看,傳統(tǒng)開發(fā)方法計(jì)劃60 d完成的工作量?jī)H需10 d左右即可完成,工作的效率提高了80%以上,文中方法達(dá)到了軟件高效快速開發(fā)的目的。文中方法可在C#、Java等平臺(tái)軟件開發(fā)中變通使用。
西安工業(yè)大學(xué)學(xué)報(bào)2019年6期