国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 開發(fā) > 綜合 > 正文

如何開發(fā)一個(gè)可復(fù)用的軟件系統(tǒng)

2024-07-21 02:16:21
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

如何創(chuàng)建一個(gè)可復(fù)用軟件系統(tǒng)

譯者序:本文是設(shè)計(jì)模式“template method”模板方法的一個(gè)延伸,將模板應(yīng)用到了整個(gè)軟件開發(fā)產(chǎn)品。首先將軟件產(chǎn)品核心不變的業(yè)務(wù)邏輯部分抽象出來(lái),對(duì)于在不同產(chǎn)品中的不同的部分,核心產(chǎn)品通過(guò)鉤子調(diào)用鉤子組件重的具體實(shí)現(xiàn),這樣開發(fā)不同的系統(tǒng)時(shí),只要更改鉤子組件的內(nèi)容就實(shí)現(xiàn)了不同的產(chǎn)品。開發(fā)的關(guān)鍵就是抽象核心產(chǎn)品的功能。當(dāng)然這種開發(fā)思想也是局限的,不是適合所有的開發(fā)項(xiàng)目(抽象所有項(xiàng)目的核心是沒(méi)有意義的),這種開發(fā)思路比較適合針對(duì)于一個(gè)領(lǐng)域的產(chǎn)品開發(fā),同一個(gè)領(lǐng)域抽象出來(lái)的核心產(chǎn)品才有實(shí)際的使用價(jià)值。



創(chuàng)建可復(fù)用的組件是學(xué)習(xí)如何創(chuàng)建可復(fù)用程序的第一步――――by mike cahn

如果你連續(xù)的開發(fā)幾個(gè)軟件項(xiàng)目,將會(huì)發(fā)現(xiàn)自己編寫了許多重復(fù)功能的代碼,當(dāng)你認(rèn)識(shí)到這點(diǎn),你肯定會(huì)產(chǎn)生復(fù)用代碼的想法。事實(shí)上很多開發(fā)團(tuán)隊(duì)都建立了自己的代碼庫(kù)和組建庫(kù)以方便的將他們應(yīng)用到新的項(xiàng)目中。下面我將講述如何將復(fù)用提高到一個(gè)更高的級(jí)別:復(fù)用整個(gè)應(yīng)用程序

如果你開發(fā)一個(gè)particular business函數(shù)或者specific vertical market,你就會(huì)發(fā)現(xiàn)客戶的需求之間存在著很多重復(fù)使用核心代碼的組件的重疊,但是需求之間的不同點(diǎn)卻要求你不得不為每一個(gè)客戶開發(fā)一個(gè)全新的系統(tǒng)

尤其不幸的是重寫會(huì)增加設(shè)計(jì)和開發(fā)時(shí)間還有更復(fù)雜的維護(hù),例如如果你存在多個(gè)版本,你就會(huì)面對(duì)這樣的問(wèn)題:傳播一個(gè)bug修復(fù)、產(chǎn)品增加功能要求為每一個(gè)客戶指定更改和測(cè)試,復(fù)用組建幫助等!但是如果所有應(yīng)用程序的核心邏輯是相同的,那為什么不更好的復(fù)用這部分核心邏輯呢?

答案是你當(dāng)然可以做到,開發(fā)一個(gè)核心產(chǎn)品,然后在不同的功能層之間你都可以使用它而沒(méi)有必要改變核心代碼

什么是鉤子?

一個(gè)鉤子就是你設(shè)置客戶實(shí)例化代碼的地方,它是一個(gè)叢核心產(chǎn)品調(diào)用到定制組件的方法,一個(gè)客戶化層(鉤子組件)需要知道正在發(fā)生什么的地方,或者需要修改核心產(chǎn)品行為的地方,你的核心產(chǎn)品都可以使用鉤子調(diào)用

典型的應(yīng)用是:一個(gè)鉤子方法通過(guò)數(shù)據(jù)和鉤子組件當(dāng)前的上下文關(guān)聯(lián)性進(jìn)行調(diào)用,鉤子組件處理這個(gè)調(diào)用以返回正確的信息

當(dāng)設(shè)計(jì)核心產(chǎn)品和鉤子組件時(shí),你要讓它們盡量保持松耦合關(guān)系,將來(lái)如果核心產(chǎn)品發(fā)生變化不會(huì)影響已經(jīng)配置的鉤子組件。你也要必須保證在配置鉤子組件時(shí),核心產(chǎn)品增加計(jì)劃范圍之外新的鉤子調(diào)用后 鉤子組件也能執(zhí)行正確的事件

確定核心功能:

使用鉤子創(chuàng)建一個(gè)核心應(yīng)用程序時(shí),評(píng)定的第一步就是確定哪些東西將要作為核心來(lái)處理,如果核心產(chǎn)品設(shè)置了太少的功能,那么你將不得不針對(duì)每一個(gè)項(xiàng)目重復(fù)執(zhí)行通用的功能,這樣增加了很大的工作量!重復(fù)的代碼操作破壞了核心應(yīng)用程序開發(fā)的目的。但是如果包括了不是所有客戶都有的通用功能將是更糟糕事情,所有開發(fā)項(xiàng)目在使用核心代碼時(shí)都會(huì)產(chǎn)生很多問(wèn)題,最后你將不得不修改核心產(chǎn)品

核心產(chǎn)品后期增加可移植的功能比從中移除本來(lái)就不應(yīng)該加入的功能要有益的多,不過(guò)這樣可能會(huì)產(chǎn)生過(guò)于保守的錯(cuò)誤!能夠適合核心產(chǎn)品的功能性能夠作為一個(gè)可以共享的組件產(chǎn)生,當(dāng)你做好準(zhǔn)備時(shí)你也可以移植它

確定核心應(yīng)用程序功能性(functionality)最關(guān)鍵的是定義個(gè)一個(gè)所有客戶都通用的程序流,讓我們來(lái)看一個(gè)例子,假設(shè)你正在開發(fā)三個(gè)系統(tǒng),它們都有一個(gè)基于移動(dòng)工作項(xiàng)目的工作流,在這三個(gè)系統(tǒng)中用戶都可以通過(guò)執(zhí)行“下一步”,從一個(gè)工作項(xiàng)目執(zhí)行到下一個(gè)工作項(xiàng)目,下面是這三個(gè)系統(tǒng)的詳細(xì)不同點(diǎn):

系統(tǒng)1:這個(gè)系統(tǒng)僅僅是移動(dòng)工作項(xiàng)目到下一步,但是不執(zhí)行任何操作

系統(tǒng)2:系統(tǒng)在一個(gè)授權(quán)(legacy)系統(tǒng)中記錄工作項(xiàng)目和操作步驟的詳細(xì)信息,同時(shí)寫入一個(gè)從授權(quán)(legacy)的系統(tǒng)到工作項(xiàng)目?jī)?nèi)部的引用關(guān)鍵字

系統(tǒng)3:系統(tǒng)在工作項(xiàng)目移動(dòng)到下一步之前顯示一個(gè)用于用戶更新的復(fù)選框,如果用戶標(biāo)志的所有必須的操作沒(méi)有成功的完成時(shí),系統(tǒng)撤銷操作“下一步”操作




圖表1顯示了功能化是如何在核心產(chǎn)品和三個(gè)不同的客戶化層之間劃分的,在這個(gè)例子中

客戶化層需要下面的能力:

使用和更新核心產(chǎn)品對(duì)象(在這個(gè)例子中指工作項(xiàng)目)

用使用者進(jìn)行交互

改變核心產(chǎn)品的工作流(比如撤銷當(dāng)前操作)

連接其他應(yīng)用程序或者組件

這些需求是很典型的,你要在你的核心產(chǎn)品的所有函數(shù)中考慮到

構(gòu)建鉤子接口:

在鉤子組件內(nèi)部設(shè)置的參數(shù)依賴上下文改變,要比維護(hù)一堆鉤子接口強(qiáng)的多,所以創(chuàng)建一個(gè)通用的鉤子接口是較好的解決方案. 使用變量集合或者參數(shù)數(shù)組適應(yīng)你將加入的不同數(shù)據(jù)類型,在第一個(gè)參數(shù)中存儲(chǔ)鉤子的標(biāo)志符,鉤子組件工作的第一件事就是解釋這個(gè)標(biāo)志符然后調(diào)用相應(yīng)的函數(shù)或者組件,下面的代碼通過(guò)使用select …..case 結(jié)構(gòu)實(shí)現(xiàn)了這一功能:

列表1:核心產(chǎn)品調(diào)用鉤子組件(一個(gè)很小的鉤子組件)

'constants would normally be defined in a module or class
const nextstep_start = "ns-start"
const nextstep_selected = "ns-selected"
const hook_ok = "ok"
const hook_cancel = "cancel"
'...

'user just selected next step operation
shookresponse = mobjhookcomponent.callin(nextstep_start, _
mobjcurrentitem, mobjcurrentuser, "")
...
'user just selected the step to move the item to
shookresponse = mobjhookcomponent.callin(nextstep_selected, _
mobjcurrentitem, mobjcurrentuser, sselectedstep)

hook component code:
'note: hook constants file would need to be included

function callin(byval shookid as string, vparam1 as variant, _
vparam2 as variant, vparam3 as variant) as string

dim sreturnvalue as string
dim objworkitem as clsworkitem
dim objuser as clsuser
dim sselectedstep as string

on error goto callin_handler

select case shookid

case nextstep_start
'processing to be done when nextstep is first invoked
set objworkitem = vparam1
set objuser = vparam2
call writelog( shookid, "item id: " & _
objworkitem.workitemid & ", user id: " & _
objuser.userid )
shookid = hook_ok
case nextstep_selected
set objworkitem = vparam1
set objuser = vparam2
sselectedstep = vparam3
call writelog( shookid, "item id: " & _
objworkitem.workitemid & ", user id: " & _
objuser.userid & ", step: " & vparam3 )

'...do whatever processing is required...
shookid = hook_ok

case else
'unknown hook, possibly introduced to product
' after this component was written.
'just allow it, but do nothing.
call writelog( shookid, "unrecognised hook" )
sreturnvalue = hook_ok
end select

callin = sreturnvalue

exit function

callin_handler:
'handle the error...

end function

sub writelog( shookid as string, stext as string )
dim sfulltext as string

sfulltext = time$ & " " & shookid & " " & stext

debug.print sfulltext

'log to file used mainly for testing
'and for diagnosing production systems
if isfileloggingon(shookid) then
'output log info to text file...
end if
end sub (to be continue )

你也可以使用你熟悉的com 實(shí)現(xiàn)這個(gè)功能,他們通過(guò)分派調(diào)用方法的技術(shù)很相似



你在發(fā)行新版本的核心產(chǎn)品時(shí)必須保證不需要重新編譯已經(jīng)存在的鉤子組件,所以鉤子組件應(yīng)該忽視所有沒(méi)有被公認(rèn)的鉤子標(biāo)志符而且僅僅返回一個(gè)簡(jiǎn)單的“成功”代碼(參考代碼列表的case else 部分),通過(guò)這個(gè)方法,鉤子組件只需為功能需求執(zhí)行被認(rèn)可的鉤子調(diào)用,如果日后需要為核心產(chǎn)品增加新的鉤子調(diào)用點(diǎn)時(shí),既有的鉤子組件不需要改變?nèi)魏涡袨榫涂梢栽黾有碌你^子標(biāo)志符

在“下一步”的例子中,核心產(chǎn)品可能在幾個(gè)執(zhí)行點(diǎn)調(diào)用鉤子,例如:當(dāng)用戶請(qǐng)求下一步操作然后選擇步驟名稱再次請(qǐng)求,這兩個(gè)例子將會(huì)是:

hook
param1
param2
param3
param4

next step started
"ns-start"
objuser
objworkitem
""

next step step selected
"ns-selected"
objuser
objworkitem
sstepname




這樣簡(jiǎn)單的一個(gè)例子,三個(gè)變量(加上鉤子標(biāo)識(shí)符)可能就已經(jīng)足夠了,可是為了避免了將

來(lái)接口改變帶來(lái)的麻煩,你總是不得不增加更多的函數(shù),列表1顯示了一個(gè)核心產(chǎn)品的簡(jiǎn)單

代碼:一個(gè)鉤子組件,一個(gè)鉤子的調(diào)用實(shí)例

為了執(zhí)行客戶三個(gè)復(fù)選框的功能,你應(yīng)該從鉤子組件項(xiàng)目中添加一個(gè)復(fù)選框窗體,并且通過(guò)

下面代碼調(diào)用:

case nextstep_selected

'...cast variables and call writelog()...

'show the checklist
frmchecklist.show vbmodal
if frmchecklist.allrequireditemsticked then
sreturnvalue = hook_ok
else
msgbox "you have not ticked all the " & _
"required items. " & _
"next step cannot continue", vbexclamation
call writelog( shookid, "cancel sent back -- " & _
"all required items not ticked" )
sreturnvalue = hook_cancel
end if
' ... more code
鉤子組件影響核心產(chǎn)品:

核心產(chǎn)品為可能發(fā)生變化的需求設(shè)置點(diǎn),然后將對(duì)他們的控制委托給鉤子組件,接著響應(yīng)鉤

子組件返回的狀態(tài),

數(shù)據(jù)對(duì)象引用

當(dāng)鉤子組件接收到一個(gè)對(duì)數(shù)據(jù)對(duì)象的引用時(shí),核心產(chǎn)品需要捕獲鉤子組件引起了什么變化,

如果你不想鉤子組件修改一個(gè)對(duì)象的參數(shù),可以通過(guò)使用一個(gè)宣傳對(duì)象或者鎖對(duì)象,或者一

個(gè)在調(diào)用方法前設(shè)置部分特性的對(duì)象,如果你允許改變,對(duì)象可以驗(yàn)證他們,或者記錄他們,

當(dāng)方法返回時(shí)通過(guò)核心產(chǎn)品驗(yàn)證他們,例如用戶需要用兩個(gè)鉤子更新一個(gè)有引用關(guān)鍵字的工

作項(xiàng)目

case nextstep_selected
'...cast variables and call writelog()...
srefkey = getmainframekey(objworkitem.workitemid)
objworkitem.reference = srefkey
sreturnvalue = hook_ok
然后核心產(chǎn)品可以查詢返回的工作項(xiàng)目對(duì)象:

mobjcurrentitem.resetchangedflag

shookresponse = _
mobjhookcomponent.callin(nextstep_selected, _
mobjcurrentuser, mobjcurrentitem, sselectedstep)

if mobjcurrentitem.changed then
'take appropriate action, such as validating
'and/or saving the changes...
end if
邏輯控制

鉤子組件可以返回影響核心產(chǎn)品邏輯的值,這種執(zhí)行方法是很有限的,例如:可以指定

一組鉤子組件返回的標(biāo)志(取消當(dāng)前操作,顯示標(biāo)準(zhǔn)對(duì)話框),否則你的核心產(chǎn)品和鉤子組

件就會(huì)產(chǎn)生緊耦合危險(xiǎn)。通過(guò)預(yù)定義一組客戶之間不需要改表的標(biāo)志,你就可以為核心產(chǎn)品

捕獲任何可能返回的值

使用交互

在一個(gè)基于windows 窗體的典型應(yīng)用程序中,鉤子組件可以用vb窗體發(fā)行,當(dāng)用戶需要時(shí)

交互調(diào)用

對(duì)于web應(yīng)用程序,核心產(chǎn)品和鉤子組件需要在服務(wù)器上運(yùn)行,所以vb 窗體就不適用了,

不過(guò)你可以用下面的幾種方法 :

通過(guò)為核心產(chǎn)品返回一個(gè)url ,來(lái)調(diào)用一個(gè)新的window瀏覽器,將一個(gè)調(diào)用瀏覽窗口的

url 返回給核心產(chǎn)品,所有從這個(gè)窗口的后繼請(qǐng)求都能被非核心調(diào)用。因?yàn)檫@個(gè)窗口是非模

式化的,所以用戶很清楚的在核心產(chǎn)品屏幕和鉤子窗口間進(jìn)行嵌套

第一步操作的一個(gè)變量用一個(gè)鉤子的url內(nèi)容臨時(shí)替換核心產(chǎn)品的瀏覽器,這是一個(gè)很

有效的模式接口,通過(guò)屏幕的請(qǐng)求可以被定制的組件捕獲,當(dāng)控制被返回到核心產(chǎn)品時(shí),控

制可以存儲(chǔ)自己的屏幕

返回一個(gè)html 或者xml 給核心產(chǎn)品,可以合并成正在創(chuàng)建的頁(yè)面,這使得鉤子接口通

過(guò)使用核心產(chǎn)品而變得更好,然而核心產(chǎn)品不得不將請(qǐng)求從屏幕的鉤子部分轉(zhuǎn)化為相應(yīng)的定

制組件

實(shí)踐:

二進(jìn)制兼容性確保了你的核心產(chǎn)品和鉤子組件總是使用相同的接口,可以在辦公室特定

的電腦上記錄你創(chuàng)建的核心產(chǎn)品,項(xiàng)目小組也經(jīng)常在站點(diǎn)上創(chuàng)建鉤子組件,使任何計(jì)算機(jī)

都變得可用。這樣有時(shí)候可以引起二進(jìn)制很難修復(fù)的問(wèn)題,如果你這樣運(yùn)行,要盡量同步

這兩個(gè)創(chuàng)建環(huán)境,盡量包含服務(wù)組件。如果還是不能正常工作,也可以放棄二進(jìn)制兼容性,

使用更緩慢的后期綁定作為最后的手段

測(cè)試:

鉤子組件提供很有用的調(diào)試和測(cè)試幫助,就像演示過(guò)的那樣,你的基本鉤子組件分之應(yīng)該要記錄所有的調(diào)用和參數(shù),響應(yīng)每個(gè)鉤子的典型方法是為每一個(gè)客戶定制代碼,然而即使是一個(gè)內(nèi)部使用,編寫一個(gè)可配置的鉤子組件也是值得的。組件的行為不是硬編碼的,它的響應(yīng)是通過(guò)list2配置文件控制的(使用xml 文件是因?yàn)樗梢园粋€(gè)可分級(jí)的信息)。你已經(jīng)編寫了一個(gè)可配置的鉤子組件,你為了測(cè)試不同的情形而不得不改變它,你將只需要修改這個(gè)配置文件。這樣的修改對(duì)開發(fā)者是很容易的,對(duì)測(cè)試者也有很顯著的用處,他們都不用修改代碼。

你的可配置鉤子允許你可以為每一個(gè)鉤子標(biāo)志符指定不同的返回值,通過(guò)為每一個(gè)基本用戶定義行為的例子精確到了一比特。我還添加了一個(gè)暫停設(shè)置和用于顯示的消息框,這對(duì)模擬延遲是很用的,

最后我還添加了一個(gè)解釋鉤子組件如何改變傳入?yún)?shù)的設(shè)置(請(qǐng)看代碼列表2)

發(fā)布:

如果沒(méi)有除了日志記錄以外的功能,一定要記住你必須至少提交和核心產(chǎn)品一致的鉤子組件分支,因?yàn)槟愕暮诵漠a(chǎn)品需要能夠調(diào)用執(zhí)行它

更多的參考:

這個(gè)鉤子概念是基于”模板”設(shè)計(jì)模式的,如果你沒(méi)有聽過(guò)這個(gè)設(shè)計(jì)模式,你應(yīng)該讀“設(shè)計(jì)模式”這本書,他們假設(shè)你使用的是一個(gè)有完全繼承功能的語(yǔ)言,雖然這不是必要的。通過(guò)vb.net 我們可以實(shí)現(xiàn),vb60通過(guò)一點(diǎn)點(diǎn)努力也可以實(shí)現(xiàn)這個(gè)目的如果你感覺這個(gè)文章有點(diǎn)難,你可以從stamatakis 編寫的“vb設(shè)計(jì)模式”開始,雖然它沒(méi)有覆蓋所有的模式,但是他對(duì)于vb開發(fā)者來(lái)說(shuō)是一個(gè)很好的開始



發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 新竹县| 乌兰浩特市| 屯昌县| 梁山县| 通州区| 锦州市| 历史| 连南| 桑日县| 肇源县| 阿瓦提县| 平利县| 南通市| 浪卡子县| 温州市| 桂东县| 大方县| 弥勒县| 化州市| 盈江县| 东方市| 青岛市| 襄垣县| 奈曼旗| 河北区| 巫溪县| 石阡县| 宁明县| 巨野县| 三明市| 安泽县| 博乐市| 东兰县| 教育| 铜山县| 横峰县| 云浮市| 中卫市| SHOW| 和平县| 海林市|