亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

軟件可以這樣功能擴(kuò)展

系統(tǒng) 1764 0
在所有關(guān)于軟件維護(hù)的故事中,功能的擴(kuò)展是一個(gè)永恒的話題。正因?yàn)檐浖到y(tǒng)需要功能的擴(kuò)展,需要新功能的加入,才使我們的編程需要那么多的設(shè)計(jì)??梢哉f,正是因?yàn)樾鹿δ艿臄U(kuò)展,使得原有的系統(tǒng)質(zhì)量下降;正是因?yàn)檐浖|(zhì)量的下降,才使我們需要進(jìn)行深入的分析與研究,制訂設(shè)計(jì)原則,總結(jié)設(shè)計(jì)模式;正是因?yàn)橐鉀Q軟件質(zhì)量下降的問題,經(jīng)過一番艱苦卓絕的摸索過程,我們才認(rèn)識到系統(tǒng)重構(gòu)才是解決該問題的最佳方案。

然而,事情總是這樣的,每個(gè)系統(tǒng)當(dāng)我們進(jìn)行初次的設(shè)計(jì)時(shí),設(shè)計(jì)思路、程序結(jié)構(gòu)總是比較完美的??墒钱?dāng)初次設(shè)計(jì)結(jié)束后,我們在日后的維護(hù)中,開始往系統(tǒng)里添加新功能時(shí),系統(tǒng)開始不完美了,甚至開始出現(xiàn)問題了,新增的功能總是或多或少有些水土不服。怎么辦呢?要保證每次需求的變更時(shí)軟件質(zhì)量不會(huì)下降,必須記住這樣一個(gè)原則:先重構(gòu)再添加新功能。

添加新功能前先重構(gòu)原有系統(tǒng),其目的有兩個(gè):
1. 軟件的設(shè)計(jì)總是與軟件的復(fù)雜程度有關(guān)的,原有的設(shè)計(jì)是在原有需求不復(fù)雜的條件下做出的,但隨著新功能的加入,軟件復(fù)雜度在發(fā)生著變化,因此必須要調(diào)整原有的設(shè)計(jì)以適應(yīng)新的需求;
2. 為了提高軟件的可維護(hù)性與易變更性,添加新功能應(yīng)遵循OCP原則。而要遵循OCP原則,我們應(yīng)當(dāng)在不添加新功能的前提下先進(jìn)行重構(gòu),設(shè)計(jì)出可擴(kuò)展點(diǎn)出來,然后再添加新功能。

是的,明白這兩點(diǎn)非常重要。軟件維護(hù)越來越困難,不是因?yàn)榭蛻籼岢隽诵枨笞兏?,而是因?yàn)槲覀儧]有隨著軟件復(fù)雜度的增加改變我們的軟件結(jié)構(gòu)。軟件需求起初比較簡單,是幾乎所有軟件的共性。但隨著軟件復(fù)雜度的增加,我們卻不敢有效地調(diào)整現(xiàn)有的軟件結(jié)構(gòu),以適應(yīng)新的需求,這就真正是我們的問題了。不敢調(diào)整,是害怕原有功能會(huì)出錯(cuò),但不調(diào)整,則意味著我們軟件設(shè)計(jì)的問題會(huì)越來越大,進(jìn)而越來越難于維護(hù)。改與不改,我們面臨著兩難的抉擇。

解決這個(gè)兩難的難題其實(shí)不難,實(shí)際上就是一層窗戶紙一桶就破了。試想,我們不敢修改原有代碼的真正原因是因?yàn)楹ε赂某鰡栴}影響原有功能的正常運(yùn)行。那么,我們找一個(gè)方法使我們在修改原有代碼時(shí)不會(huì)出現(xiàn)問題,換句話說是出現(xiàn)問題以后會(huì)及時(shí)發(fā)現(xiàn),則問題就可以解決,這個(gè)方法就是重構(gòu)與測試。

客戶判斷一個(gè)功能是否正常運(yùn)行的標(biāo)準(zhǔn),就是當(dāng)輸入一個(gè)值后,能得到客戶期望的結(jié)果,不管系統(tǒng)內(nèi)部是怎樣運(yùn)行的。因此,建立這樣一個(gè)測試用例,讓軟件系統(tǒng)在重構(gòu)前后都能通過這些測試用例,就可以保證重構(gòu)的正確性(關(guān)于如何建立,我們還會(huì)在后面仔細(xì)討論)。重構(gòu)以后,外部功能是一致的,但內(nèi)部程序結(jié)構(gòu)卻變得更加易于添加新的功能,使新的功能與原有系統(tǒng)可以有機(jī)地融為一體,這才是我們的目的。說起來比較抽象,我們來舉一個(gè)示例吧:

在許多系統(tǒng)中,只要有報(bào)表出現(xiàn)就有需求要實(shí)現(xiàn)Excel數(shù)據(jù)導(dǎo)出功能。在一個(gè)系統(tǒng)中,客戶起初提出的需求是實(shí)現(xiàn)“全部導(dǎo)出”、“按選擇導(dǎo)出”、“導(dǎo)出本頁”。為此,我們設(shè)計(jì)了一個(gè)單選框,并在后臺(tái)程序中編寫了一個(gè)if語句,如果選擇的是“全部導(dǎo)出”,則查詢所有記錄并導(dǎo)出;如果選擇的是“按選擇導(dǎo)出”,則從前端獲得一個(gè)主鍵列表,即用戶已選擇的行,以此作為條件查詢導(dǎo)出;如果選擇的是“導(dǎo)出本頁”,則查詢本頁數(shù)據(jù)并導(dǎo)出。
    
	String exportTypeName = (String)params.get("exportType");
	if("exportAll".equals(exportTypeName)) {
		//全部導(dǎo)出的代碼
	} else if("exportChoosen".equals(exportTypeName)) {
		//按選擇導(dǎo)出的代碼
	} else if("exportOnePage".equals(exportTypeName)) {
		//導(dǎo)出本頁的代碼
	}

  

這樣的設(shè)計(jì)沒有問題,也是大多數(shù)人首先想到的設(shè)計(jì)。但是,多個(gè)不同的選擇放在一個(gè)類中必將為功能的擴(kuò)展帶來麻煩。隨后,客戶提出了新的需求,按頁導(dǎo)出,即根據(jù)客戶的要求,從第幾頁到第幾頁進(jìn)行導(dǎo)出。按照前面的設(shè)計(jì),我們必然是在原有基礎(chǔ)上再增加一個(gè)if語句,實(shí)現(xiàn)按頁導(dǎo)出。
    
	String exportTypeName = (String)params.get("exportType");
	if("exportAll".equals(exportTypeName)) {
		//全部導(dǎo)出的代碼
	} else if("exportChoosen".equals(exportTypeName)) {
		//按選擇導(dǎo)出的代碼
	} else if("exportOnePage".equals(exportTypeName)) {
		//導(dǎo)出本頁的代碼
	} else if("exportPageRange".equals(exportTypeName)) {
		//按頁導(dǎo)出的代碼
	}

  

但這樣的設(shè)計(jì)違反了OCP原則,也是大多數(shù)系統(tǒng)代碼質(zhì)量下降的重要原因之一。在一些文章中,if語句被稱為“罪惡之源”,因?yàn)榇罅渴褂胕f語句將會(huì)大大降低系統(tǒng)的可讀性、可維護(hù)性與易變更性,使系統(tǒng)難于維護(hù)。因?yàn)椴粩嗵砑拥膇f語句很快會(huì)使代碼由數(shù)百行膨脹到幾千行,還會(huì)大量摻雜各種重復(fù)代碼與糟糕設(shè)計(jì)。其根本原因就在于,它讓一個(gè)類承載了過多的職責(zé),降低了功能內(nèi)聚而提高了功能耦合。它不僅加大了我們修改代碼的難度,也將加大我們測試代碼的成本,因?yàn)槿魏我豁?xiàng)修改都必須要對所有功能進(jìn)行測試。

因此,我們需要調(diào)整我們的代碼結(jié)構(gòu),改變我們的設(shè)計(jì)(到這里也許你開始理解我所說的改變代碼結(jié)構(gòu)以適應(yīng)新的需求的含義了吧)。我們說擴(kuò)展新功能的設(shè)計(jì)應(yīng)當(dāng)符合OCP原則。怎樣的設(shè)計(jì)才是符合OCP原則的呢?首先可以想到的是,讓“按頁導(dǎo)出”這個(gè)功能的代碼放到另一個(gè)類中,而不寫在原有類中。比如,我們可以創(chuàng)建一個(gè)新類ExportPageRange,通過接口Exporter接入到原類ExportBus,讓ExportBus調(diào)用其相應(yīng)的方法:



但是,這樣的設(shè)計(jì)我們依然需要修改原類ExportBus,在if語句中調(diào)用接口:
    
	String exportTypeName = (String)params.get("exportType");
	If ("exportAll".equals(exportTypeName)) {
		//全部導(dǎo)出的代碼
	} else if ("exportChoosen".equals(exportTypeName)) {
		//按選擇導(dǎo)出的代碼
	} else if ("exportOnePage".equals(exportTypeName)) {
		//導(dǎo)出本頁的代碼
	} else if ("exportPageRange".equals(exportTypeName)) {
		//按頁導(dǎo)出的代碼
		Exporter exporter = new ExportPageRange();
		exporter.doExport(resultset);
		return exporter.getFileInfo();
	}

  

加粗部分是我們不得不在原類中添加的代碼。如果不使用這個(gè)if語句而讓Exporter接口的實(shí)現(xiàn)類與判斷條件建立一種聯(lián)系,則問題可以得到解決。要實(shí)現(xiàn)這種聯(lián)系有很多方法,其中一個(gè)方法就是建立配置文件,讓配置文件中的名稱與實(shí)現(xiàn)類關(guān)聯(lián)起來就可以了,為此我們需要這樣設(shè)計(jì):



然后進(jìn)行這樣的配置:
    
<bean id="exportBus" class="com...reporter.bus.impl.ExportBusImpl">
	<description>導(dǎo)出數(shù)據(jù)BUS</description>
	<property name="exportTypes">
		<map>
			<entry key="exportAll"><!-- 全部導(dǎo)出 -->
				<bean class="com...reporter.export.ExportAll"/>
			</entry>
			<entry key="exportOnePage"><!-- 導(dǎo)出本頁 -->
				<bean class="com...reporter.export.ExportOnePage"/>
			</entry>
			<entry key="exportChosen"><!-- 按選擇導(dǎo)出 -->
				<bean class="com...reporter.export.ExportChosen"/>
			</entry>
			<entry key="exportPageRange"><!-- 按頁導(dǎo)出 -->
				<bean class="com...reporter.export.ExportPageRange"/>
			</entry>
		</map>
	</property>
</bean>
  


這樣,配置文件中的entrykey就與導(dǎo)出程序的實(shí)現(xiàn)類建立了聯(lián)系,因此在ExportBus中原來的那個(gè)if語句就演變成了這樣:
    
	String exportTypeName = (String)params.get("exportType");
	Exporter exporter = exportTypes.get(exportTypeName);
	exporter.doExport(resultset);
	return exporter.getFileInfo();

  

加粗的部分實(shí)質(zhì)性替代了原來那個(gè)if語句。這樣的設(shè)計(jì),讓各個(gè)不同類型的導(dǎo)出程序得到有效解耦,然后通過接口與配置文件實(shí)現(xiàn)動(dòng)態(tài)地裝配。這就是一種典型的可擴(kuò)展點(diǎn)設(shè)計(jì),當(dāng)我們還有新的導(dǎo)出類型的功能需要擴(kuò)展的時(shí)候,不需要修改原有的任何代碼,而只需添加一個(gè)Exporter接口新的實(shí)現(xiàn)類,再進(jìn)行相應(yīng)的配置,功能就可以實(shí)現(xiàn)。這樣的設(shè)計(jì)是可以滿足OCP原則的,而在系統(tǒng)中實(shí)現(xiàn)這種可擴(kuò)展性設(shè)計(jì)的功能點(diǎn),我們就稱之為“可擴(kuò)展點(diǎn)”。

以上的設(shè)計(jì)是我們最終應(yīng)當(dāng)實(shí)現(xiàn)的設(shè)計(jì),是結(jié)果。但要達(dá)到這樣的設(shè)計(jì),即分析整個(gè)設(shè)計(jì)的過程,我們真的沒有修改原程序嗎?不,我們修改了。那么這怎么叫符合OCP原則呢?問題十分犀利哈。轉(zhuǎn)了那么大一圈,現(xiàn)在才是我要真正提出我的觀點(diǎn)的時(shí)候了。我認(rèn)為,要改善遺留系統(tǒng)的可維護(hù)性,要遵守OCP原則,并不是意味著實(shí)現(xiàn)新需求時(shí)不能修改原有代碼。要遵從“兩頂帽子”的設(shè)計(jì)原則,先重構(gòu)原有的代碼,使其具有可擴(kuò)展功能,然后再添加新程序,使其滿足OCP原則,這才是可擴(kuò)展設(shè)計(jì)的關(guān)鍵之所在。

具體來說,就是第一步修改代碼,第二步添加功能。第一步,修改原有代碼,在保證原有功能不變的前提下,設(shè)計(jì)出可擴(kuò)展點(diǎn),使其在以后添加新功能時(shí)不必修改原有代碼。在本例中就是將原有的三種導(dǎo)出方式從原有代碼中抽取出來,形成Exporter接口與ExportAll、ExportOnePage、ExportChosen三個(gè)實(shí)現(xiàn)類,以及它們的配置文件。這樣,Exporter接口就是數(shù)據(jù)導(dǎo)出方式的可擴(kuò)展點(diǎn)。這時(shí),由于沒有添加任何新功能,我們可以編寫測試代碼進(jìn)行測試,或者手工測試。

第二步,就是添加新功能。由于可擴(kuò)展點(diǎn)已經(jīng)做出來了,剩下的工作其實(shí)就很簡單了:編寫實(shí)現(xiàn)類ExportPageRange,然后配置到系統(tǒng)中,整個(gè)設(shè)計(jì)符合OCP原則。功能擴(kuò)展就應(yīng)當(dāng)這樣做,才能使我們的軟件在維護(hù)中始終能保持高質(zhì)量的代碼。
(續(xù))

相關(guān)文檔
遺留系統(tǒng):IT攻城獅永遠(yuǎn)的痛
需求變更是罪惡之源嗎?
系統(tǒng)重構(gòu)是個(gè)什么玩意兒
我們應(yīng)當(dāng)改變我們的設(shè)計(jì)習(xí)慣
小步快跑是這樣玩的(上)
小步快跑是這樣玩的(下)
代碼復(fù)用應(yīng)該這樣做(1)
代碼復(fù)用應(yīng)該這樣做(2)
代碼復(fù)用應(yīng)該這樣做(3)
做好代碼復(fù)用不簡單
軟件可以這樣功能擴(kuò)展
過程擴(kuò)展與放置鉤子

特別說明:希望網(wǎng)友們在轉(zhuǎn)載本文時(shí),應(yīng)當(dāng)注明作者或出處,以示對作者的尊重,謝謝!

軟件可以這樣功能擴(kuò)展


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯(lián)系: 360901061

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會(huì)非常 感謝您的哦?。。?/p>

發(fā)表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 天天插天天干 | 亚洲欧美在线观看91偷拍 | 4hu影院在线观看 | 久草香蕉在线视频 | 国产精品久久久视频 | 日韩a无吗一区二区三区 | 摸逼综合网 | 狠狠躁夜夜躁人人爽天天miya | 九色国产在视频线精品视频 | 欧美成人性视频在线黑白配 | 香蕉视频免费在线观看 | 日本在线色 | 国产国产精品四虎视频精品 | 国产成人福利在线 | 欧美午夜艳片欧美精品 | 精品国产一区二区三区www | 亚洲 中文 欧美 日韩 在线人 | 国产精品亚洲欧美大片在线看 | 四虎永久在线精品2022 | 99精品国产综合久久久久 | 中文字幕中韩乱码亚洲大片 | 国产欧美精品午夜在线播放 | 中文字幕一区二区三区永久 | 欧美成人禁片在线观看网址 | 欧美一区二区三区不卡片 | 人喾交性专区免费看 | 欧美妇性猛交视频 | 天天操中文字幕 | 亚洲 欧美 另类 天天更新影院 | 久久亚洲国产成人精品性色 | 亚洲日产2021三区在线 | 农村寡妇一级毛片免费看视频 | 欧美在线观看视频 | 欧美经典人人爽人人爽人人片 | 在线综合 亚洲 欧美中文字幕 | 12345国产精品高清在线 | 亚洲字幕久久 | 亚洲综合专区 | 国产区成人综合色在线 | 九九香蕉视频 | 国产在线精品香蕉麻豆 |