軟件復(fù)用是將已有的軟件及其有效成分用于構(gòu)造新的軟件或系統(tǒng)。它不僅是對(duì)軟件程序的復(fù)用,還包括對(duì)軟件生產(chǎn)過(guò)程中其它勞動(dòng)成果的復(fù)用,如項(xiàng)目計(jì)劃書(shū)、可行性報(bào)告、需求分析、概要設(shè)計(jì)、詳細(xì)設(shè)計(jì)、編碼
(
源程序
)
、測(cè)試用例、文檔與使用手冊(cè)等等。面對(duì)越來(lái)越復(fù)雜的業(yè)務(wù)邏輯,軟件復(fù)用技術(shù)一直以來(lái)都是業(yè)界關(guān)注的焦點(diǎn),相關(guān)理論和技術(shù)層出不窮。作為一種比較出色的實(shí)現(xiàn)
MVC
設(shè)計(jì)模式的
FrameWork
,
Jakarta Struts
提供了一種比較理想的軟件復(fù)用方法。在
LPMT
中,我們對(duì)其中的代碼復(fù)用進(jìn)行了有益的嘗試。
這里的
Model
包括所有的
Action
類、
ActionForm
類。
在
LPMT
中,我們?cè)O(shè)計(jì)了兩個(gè)
Action
:
IssueAction
和
MainAction
。其中,
IssueAction
負(fù)責(zé)
IssueAction
及
IssueData
、
ChangeLog
操作,
MainAction
負(fù)責(zé)
User
及
Login
操作,據(jù)此實(shí)現(xiàn)
Action
復(fù)用。在每個(gè)
Action
中,通過(guò)參數(shù)
action
的值來(lái)判斷操作的類型,繼而實(shí)現(xiàn)相應(yīng)的業(yè)務(wù)邏輯操作;
IssueAction
:
//
查看所有的
Issue
?if(("view".equals(action)) || (action == null)) {
}
?//
查看單個(gè)
Issue
及其
IssueDatas
和
ChangeLogs
?else if("viewDetail".equals(action)) {
}
?//
新建一個(gè)
Issue
?else if("create".equals(action)) {
}
?//
編輯已有的
Issue
?else if("edit".equals(action)) {
}
?//
刪除對(duì)應(yīng)的
Issue
?else if("delete".equals(action)) {
}
?//
保存新建的
Issue
?else if("save".equals(action)) {
}
?//
新建
IssueData
?else if("createIssueData".equals(action)) {
}
?//
保存新建的
IssueData
?else if("saveIssueData".equals(action)) {
}
?//
編輯
IssueData
?else if("editIssueData".equals(action)) {
}
?//
刪除
IssueData
?else if("deleteIssueData".equals(action)) {
}
MainAction
:
??? //
判斷用戶是否取消操作
,
是則就轉(zhuǎn)向
main.jsp
??? if(this.isCancelled(request))
??? {
??? }
??? //
登陸
??? if(request.getParameter("action").equals("login"))
??? {
??? }
??? //
顯示添加新用戶界面
??? if(request.getParameter("action").equals("newUser"))
??? {
??? }
??? //
添加新用戶
??
?if(request.getParameter("action").equals("doNewUser"))
??? {
??? }
??? //
顯示要修改的用戶的資料
??? if(request.getParameter("action").equals("updateUser"))
??? {
??? }
??? //
修改用戶資料
??? if(request.getParameter("action").equals("doUpdateUser"))
??? {
??? }
??? //
判斷是否要?jiǎng)h除用戶
??? if(request.getParameter("action").equals("deleteUser"))
??? {
??? }
??? //
刪除用戶
??? if(request.getParameter("action").equals("doDeleteUser"))
??? {
??? }
??? //
查看用戶列表
??? if(request.getParameter("action").equals("viewUser"))
??? {
??? }
通過(guò)參數(shù)
address
來(lái)保留下一步的映射目標(biāo);在
struts-config.xml
配置文件中,我們通過(guò)
global-forward
和
action-forward
映射,將不同的
address
映射到相應(yīng)的目標(biāo)
View
。
?
?? <global-forwards>
???
????? <forward name="loginSuccess" path="/main.jsp" />
???
????? <forward name="newUser" path="/newUser.jsp"/>
???
????? <forward name="updateUser" path="/newUser.jsp"/>
???
????? <forward name="deleteUser" path="/deleteUser.jsp"/>
???
????? <forward name="login" path="/index.jsp"/>
???
????? <forward name="success" path="/message.jsp"/>
??????
?????? <forward name="operationSuccess" path="/Success.jsp" />
???
????? <forward name="error" path="/error.jsp"/>
???
????? <forward name="viewUser" path="/viewUser.jsp"/>
?
?? </global-forwards>
??? <action name="issueActionForm" type="issuecontrol.action.IssueAction" validate="false" scope="request" path="/issueAction">
?????
? <forward name="viewIssue" path="/IssueList.jsp" />
?????
? <forward name="viewIssueDetail" path="/IssueDetail.jsp" />
?????
? <forward name="issueData" path="/IssueData.jsp" />
</action>
在必要的時(shí)候,
IssueAction
和
MainAction
可以合為一個(gè)
Action
,由這個(gè)
Action
來(lái)負(fù)責(zé)所有業(yè)務(wù)邏輯操作。
在面向?qū)ο笤O(shè)計(jì)之后,對(duì)于每個(gè)需要顯示的實(shí)體對(duì)象,我們定義了一個(gè)
ActionForm
,如
IssueActionForm
、
ComponentActionForm
、
PriorityActionForm
、
TypeActionForm
、
LogActionForm
。
ActionForm
實(shí)現(xiàn)了
Serializable
接口,每個(gè)
xxxActionForm
繼承
ActionForm
類,適合用于數(shù)據(jù)封裝、顯示和遠(yuǎn)程網(wǎng)絡(luò)傳播。
通過(guò)在
struts-config.xml
中的映射,一個(gè)
Action
可以對(duì)應(yīng)多個(gè)
ActionForm
,實(shí)現(xiàn)
Action
和
ActionForm
復(fù)用。
? <form-beans>
??? <form-bean name="LoginForm" type="issuecontrol.actionform.LoginForm" />
??? <form-bean name="NewUserForm" type="issuecontrol.actionform.NewUserForm"/>
??? <form-bean name="BaseForm" type="issuecontrol.actionform.BaseForm"/>
?????? <form-bean name="loginActionForm" type="issuecontrol.actionform.LoginActionForm" />
??? <form-bean name="componentActionForm" type="issuecontrol.actionform.ComponentActionForm" />
??? <form-bean name="environmentActionForm" type="issuecontrol.actionform.EnvironmentActionForm" />
??? <form-bean name="flagActionForm" type="issuecontrol.actionform.FlagActionForm" />
??? <form-bean name="issueActionForm" type="issuecontrol.actionform.IssueActionForm" />
??? <form-bean name="logActionForm" type="issuecontrol.actionform.LogActionForm" />
??? <form-bean name="priorityActionForm" type="issuecontrol.actionform.PriorityActionForm" />
??? <form-bean name="typeActionForm" type="issuecontrol.actionform.TypeActionForm" />
??? <form-bean name="issueDataActionForm" type="issuecontrol.actionform.IssueDataActionForm"/>
? </form-beans>
? <action-mappings>
??? <action name="LoginForm" type="issuecontrol.action.MainAction" validate="true" scope="session" input="/index.jsp" path="/login" />
??? <action path="/newUser" name="BaseForm" type="issuecontrol.action.MainAction" validate="false" scope="request" input="/main.jsp"/>
??? <action path="/doNewUser" name="NewUserForm" type="issuecontrol.action.MainAction" validate="true" scope="request" input="/newUser.jsp"/>
??? <action path="/viewUser" name="BaseForm" type="issuecontrol.action.MainAction" validate="false" scope="request" input="/main.jsp"/>
??? <action path="/updateUser" name="BaseForm" type="issuecontrol.action.MainAction" validate="false" scope="request" input="/viewUser.jsp"/>
??? <action path="/doUpdateUser" name="NewUserForm" type="issuecontrol.action.MainAction" validate="true" scope="request" input="/newUser.jsp"/>
??? <action path="/deleteUser" name="BaseForm" type="issuecontrol.action.MainAction" validate="false" scope="request" input="/viewUser.jsp"/>
??? <action path="/doDeleteUser" name="BaseForm" type="issuecontrol.action.MainAction" validate="false" scope="request" input="/deleteUser.jsp"/>
??? <action name="issueActionForm" type="issuecontrol.action.IssueAction" validate="false" scope="request" path="/issueAction">
??? </action>
?????? <action name="issueDataActionForm" type="issuecontrol.action.IssueAction" validate="false" scope="request" path="/issueDataAction"/>
? </action-mappings>
這里的
View
主要是指用
Jakarta Struts
標(biāo)簽庫(kù)構(gòu)建起來(lái)的
JSP
頁(yè)面。正如本文“
LPMT
中的控制結(jié)構(gòu)”和“
WebForm
的
Jakarta Struts
標(biāo)簽技術(shù)實(shí)現(xiàn)”部分所說(shuō)的,通過(guò)
<logic:equal>
標(biāo)簽和
Action
、
ActionForm
中
action
、
actionType
參數(shù)的設(shè)置,可以很容易將創(chuàng)建、查看、修改、刪除等功能的
View
顯示集合在一個(gè)
JSP
頁(yè)面完成。理論上,可以只創(chuàng)建一個(gè)
View
,但是由此所帶來(lái)的創(chuàng)建、修改和維護(hù)成本將不合算。所以我們通常把相同或相似的業(yè)務(wù)邏輯結(jié)果顯示放在一個(gè)
View
中完成,以此實(shí)現(xiàn)
View
的復(fù)用。
Struts
的
Controller
由
ActionServlet
、
RequestProcessor
、
ActionMapping
等類組成。這些類在
Struts
中唯一充當(dāng)控制器角色,
Model
中相應(yīng)的
ActionForm
和
URL
中的參數(shù)則作為數(shù)據(jù)封裝和傳遞的媒介。這些類通過(guò)相應(yīng)的方法和接口復(fù)用,實(shí)現(xiàn)
Model
的復(fù)用。
在
LPMT
中,我們采用了面向?qū)ο蟮姆治觥⒃O(shè)計(jì)和編碼方法,因此,我們主要著眼于面向?qū)ο笏枷朐谙旅鎺讉€(gè)方面實(shí)現(xiàn)代碼復(fù)用:
7.4.1
封裝性
在軟構(gòu)件的定義中,用戶只關(guān)心事件的輸入輸出,對(duì)事件內(nèi)部不必關(guān)心,方法和事件是獨(dú)立于應(yīng)用的,用戶可以在軟構(gòu)件中定義自己的事件,對(duì)于內(nèi)部的復(fù)雜性調(diào)用這并不知曉,從而提高了隱蔽性。在
Logic
、
DataPersistence
等相關(guān)
Bean
和
DAO
類中,我們遵循數(shù)據(jù)封裝和持久原則,在
Action
中調(diào)用相關(guān)方法只要符合相應(yīng)的輸入和輸出條件即可實(shí)現(xiàn)既定的業(yè)務(wù)邏輯操作
,
而不需要了解業(yè)務(wù)邏輯的處理過(guò)程。
7.4.2
重載
重載就是在同一軟件構(gòu)件中用同一名字來(lái)表示不同的方法名。一般有兩種實(shí)現(xiàn)方法,一是方法參數(shù)的個(gè)數(shù)重載,二是方法參數(shù)的類型重載。在
IssueDAO
中,根據(jù)應(yīng)用需求,我們定義了
delOneLog
方法,通過(guò)方法參數(shù)的類型(
Log
類型、
Long
類型)不同實(shí)現(xiàn)重載。另外的
getIssueByPage
方法,則通過(guò)方法參數(shù)的個(gè)數(shù)不同實(shí)現(xiàn)重載。詳細(xì)代碼參考附錄。
7.4.3
繼承
繼承就是高層的類在不同范圍的復(fù)用。在
Web
系統(tǒng)設(shè)計(jì)中,經(jīng)常需要驗(yàn)證客戶端的輸入是否符合要求,比如輸入不能為空、
Email
段輸入必須符合規(guī)范等等。在
Model
層的
ActionForm
類中,我們定義了一個(gè)高層類
BaseForm
,
BaseForm
擴(kuò)展了
ActionForm
,定義了幾個(gè)常用的數(shù)據(jù)驗(yàn)證方法,比如驗(yàn)證輸入是否為空的
isBlankString
方法、驗(yàn)證前后輸入是否一樣的
isTheSame
等。其他的
ActionForm
通過(guò)繼承
BaseForm
實(shí)現(xiàn)。另外一種方法,可以通過(guò)定義一個(gè)
ValidateForm
的靜態(tài)類來(lái)負(fù)責(zé)常用的幾種輸入驗(yàn)證,其他
ActionForm
類在
Validate
方法中通過(guò)調(diào)用
ValidateForm
類的相應(yīng)方法即可實(shí)現(xiàn)相應(yīng)的輸入驗(yàn)證邏輯。
結(jié)論
通過(guò)上述背景闡述、技術(shù)分析和代碼實(shí)踐,可以看到,使用
Struts
構(gòu)建的實(shí)現(xiàn)了
MVC
設(shè)計(jì)模式的系統(tǒng),在提高系統(tǒng)的構(gòu)建效率、可擴(kuò)展性、可維護(hù)性、可復(fù)用性方面均有突出的表現(xiàn)。而本文在
LPMT
中的
Struts
應(yīng)用方式比如架構(gòu)設(shè)計(jì)、
WebForm
構(gòu)建技術(shù)等有效的發(fā)揮了
Struts
技術(shù)的優(yōu)勢(shì),快速實(shí)現(xiàn)了系統(tǒng)的應(yīng)用需求,有一定的參考價(jià)值。
致謝語(yǔ)
在本文寫(xiě)作和系統(tǒng)設(shè)計(jì)過(guò)程中,林勁松老師給了大量熱心的幫助和指導(dǎo),在此特別感謝。作者的同組同學(xué)范曉鑫和羅佳在系統(tǒng)設(shè)計(jì)和編碼方面也讓作者受益頗多,作者在廈門合強(qiáng)軟件有限公司的同事在
MVC
思想方面給了作者很大的提示和幫助,在此一并感謝。同時(shí)要感謝自動(dòng)化系所有的老師和同學(xué)在大學(xué)四年對(duì)作者的關(guān)心和幫助。
參考文獻(xiàn)
(1)
???
James Goodwill《Mastering Jakarta Struts》Indianapolis, Indiana,Canada Wiley Publishing ,Inc.2002年
(2)
???
Hafech Mili,Ali Mili,Sherif Yacoub etal著,韓柯譯《基于重用的軟件工程》北京電子工業(yè)出版社 2003年
(3)
???
孫琪《軟件復(fù)用技術(shù)概述》http://www.tongtech.com/jsqy/yqxwview.asp?id=209? 2003年6月30日
(4)
???
趙晨希
《用Struts建立MVC應(yīng)用的介紹》
http://www-900.ibm.com/developerWorks/cn/java/l-struts-mvc/index.shtml
?2002
年 12 月
(5)
???
劉天北 《理解企業(yè)應(yīng)用框架》http://www.socent.com/crm_oa/message.asp?id=1182003年7月1日
21MM
《框架不是框框
—
應(yīng)用框架的基本思想》
http://www.digitalspirit.info/phf/artichecture/applyFrame.htm
posted on 2005-01-27 14:53
eamoi 閱讀(2555)
評(píng)論(1) 編輯 收藏 所屬分類:
Java 、
畢業(yè)設(shè)計(jì)文檔