1_代碼重構(gòu)漫畫.jpeg
創(chuàng)新互聯(lián)是一家專注于網(wǎng)站建設(shè)、成都網(wǎng)站建設(shè)與策劃設(shè)計(jì),圖們網(wǎng)站建設(shè)哪家好?創(chuàng)新互聯(lián)做網(wǎng)站,專注于網(wǎng)站建設(shè)10多年,網(wǎng)設(shè)計(jì)領(lǐng)域的專業(yè)建站公司;建站業(yè)務(wù)涵蓋:圖們等地區(qū)。圖們做網(wǎng)站價(jià)格咨詢:13518219792
項(xiàng)目在不斷演進(jìn)過程中,代碼不停地在堆砌。如果沒有人為代碼的質(zhì)量負(fù)責(zé),代碼總是會(huì)往越來越混亂的方向演進(jìn)。當(dāng)混亂到一定程度之后,量變引起質(zhì)變,項(xiàng)目的維護(hù)成本已經(jīng)高過重新開發(fā)一套新代碼的成本,想要再去重構(gòu),已經(jīng)沒有人能做到了。
造成這樣的原因往往有以下幾點(diǎn):
對于此類問題,業(yè)界已有有很好的解決思路:通過持續(xù)不斷的重構(gòu)將代碼中的“壞味道”清除掉。
重構(gòu)一書的作者M(jìn)artin Fowler對重構(gòu)的定義:
根據(jù)重構(gòu)的規(guī)??梢源笾路譃榇笮椭貥?gòu)和小型重構(gòu):
大型重構(gòu) :對頂層代碼設(shè)計(jì)的重構(gòu),包括:系統(tǒng)、模塊、代碼結(jié)構(gòu)、類與類之間的關(guān)系等的重構(gòu),重構(gòu)的手段有:分層、模塊化、解耦、抽象可復(fù)用組件等等。這類重構(gòu)的工具就是我們學(xué)習(xí)過的那些設(shè)計(jì)思想、原則和模式。這類重構(gòu)涉及的代碼改動(dòng)會(huì)比較多,影響面會(huì)比較大,所以難度也較大,耗時(shí)會(huì)比較長,引入bug的風(fēng)險(xiǎn)也會(huì)相對比較大。
小型重構(gòu) :對代碼細(xì)節(jié)的重構(gòu),主要是針對類、函數(shù)、變量等代碼級(jí)別的重構(gòu),比如規(guī)范命名和注釋、消除超大類或函數(shù)、提取重復(fù)代碼等等。小型重構(gòu)更多的是使用統(tǒng)一的編碼規(guī)范。這類重構(gòu)要修改的地方比較集中,比較簡單,可操作性較強(qiáng),耗時(shí)會(huì)比較短,引入bug的風(fēng)險(xiǎn)相對來說也會(huì)比較小。什么時(shí)候重構(gòu) 新功能開發(fā)、修bug或者代碼review中出現(xiàn)“代碼壞味道”,我們就應(yīng)該及時(shí)進(jìn)行重構(gòu)。持續(xù)在日常開發(fā)中進(jìn)行小重構(gòu),能夠降低重構(gòu)和測試的成本。
2_代碼常見問題.png
代碼重復(fù)
方法過長
過大的類
邏輯分散
嚴(yán)重的情結(jié)依戀
數(shù)據(jù)泥團(tuán)/基本類型偏執(zhí)
不合理的繼承體系
過多的條件判斷
過長的參數(shù)列
臨時(shí)變量過多
令人迷惑的暫時(shí)字段
純數(shù)據(jù)類
不恰當(dāng)?shù)拿?/p>
過多的注釋
3_代碼質(zhì)量如何衡量.jpg
代碼質(zhì)量的評(píng)價(jià)有很強(qiáng)的主觀性,描述代碼質(zhì)量的詞匯也有很多,比如可讀性、可維護(hù)性、靈活、優(yōu)雅、簡潔。這些詞匯是從不同的維度去評(píng)價(jià)代碼質(zhì)量的。其中,可維護(hù)性、可讀性、可擴(kuò)展性又是提到最多的、最重要的三個(gè)評(píng)價(jià)標(biāo)準(zhǔn)。
要寫出高質(zhì)量代碼,我們就需要掌握一些更加細(xì)化、更加能落地的編程方法論,這就包含面向?qū)ο笤O(shè)計(jì)思想、設(shè)計(jì)原則、設(shè)計(jì)模式、編碼規(guī)范、重構(gòu)技巧等。
4_SOLID原則.png
一個(gè)類只負(fù)責(zé)完成一個(gè)職責(zé)或者功能,不要存在多于一種導(dǎo)致類變更的原因。
單一職責(zé)原則通過避免設(shè)計(jì)大而全的類,避免將不相關(guān)的功能耦合在一起,來提高類的內(nèi)聚性。同時(shí),類職責(zé)單一,類依賴的和被依賴的其他類也會(huì)變少,減少了代碼的耦合性,以此來實(shí)現(xiàn)代碼的高內(nèi)聚、松耦合。但是,如果拆分得過細(xì),實(shí)際上會(huì)適得其反,反倒會(huì)降低內(nèi)聚性,也會(huì)影響代碼的可維護(hù)性。
添加一個(gè)新的功能,應(yīng)該是通過在已有代碼基礎(chǔ)上擴(kuò)展代碼(新增模塊、類、方法、屬性等),而非修改已有代碼(修改模塊、類、方法、屬性等)的方式來完成。
開閉原則并不是說完全杜絕修改,而是以最小的修改代碼的代價(jià)來完成新功能的開發(fā)。
很多設(shè)計(jì)原則、設(shè)計(jì)思想、設(shè)計(jì)模式,都是以提高代碼的擴(kuò)展性為最終目的的。特別是 23 種經(jīng)典設(shè)計(jì)模式,大部分都是為了解決代碼的擴(kuò)展性問題而總結(jié)出來的,都是以開閉原則為指導(dǎo)原則的。最常用來提高代碼擴(kuò)展性的方法有:多態(tài)、依賴注入、基于接口而非實(shí)現(xiàn)編程,以及大部分的設(shè)計(jì)模式(比如,裝飾、策略、模板、職責(zé)鏈、狀態(tài))。
子類對象(object of subtype/derived class)能夠替換程序(program)中父類對象(object of base/parent class)出現(xiàn)的任何地方,并且保證原來程序的邏輯行為(behavior)不變及正確性不被破壞。
子類可以擴(kuò)展父類的功能,但不能改變父類原有的功能
調(diào)用方不應(yīng)該依賴它不需要的接口;一個(gè)類對另一個(gè)類的依賴應(yīng)該建立在最小的接口上。接口隔離原則提供了一種判斷接口的職責(zé)是否單一的標(biāo)準(zhǔn):通過調(diào)用者如何使用接口來間接地判定。如果調(diào)用者只使用部分接口或接口的部分功能,那接口的設(shè)計(jì)就不夠職責(zé)單一。
高層模塊不應(yīng)該依賴低層模塊,二者都應(yīng)該依賴其抽象;抽象不應(yīng)該依賴細(xì)節(jié),細(xì)節(jié)應(yīng)該依賴抽象。
一個(gè)對象應(yīng)該對其他對象保持最少的了解
盡量使用合成/聚合的方式,而不是使用繼承。
單一職責(zé)原則告訴我們實(shí)現(xiàn)類要職責(zé)單一;里氏替換原則告訴我們不要破壞繼承體系;依賴倒置原則告訴我們要面向接口編程;接口隔離原則告訴我們在設(shè)計(jì)接口的時(shí)候要精簡單一;迪米特法則告訴我們要降低耦合。而開閉原則是總綱,告訴我們要對擴(kuò)展開放,對修改關(guān)閉。
image.png
模塊結(jié)構(gòu)說明
代碼開發(fā)要遵守各層的規(guī)范,并注意層級(jí)之間的依賴關(guān)系。
多個(gè)方法代碼重復(fù)、方法中代碼過長或者方法中的語句不在一個(gè)抽象層級(jí)。
方法是代碼復(fù)用的最小粒度,方法過長不利于復(fù)用,可讀性低,提煉方法往往是重構(gòu)工作的第一步。
意圖導(dǎo)向編程 :把處理某件事的流程和具體做事的實(shí)現(xiàn)方式分開。
將函數(shù)放進(jìn)一個(gè)單獨(dú)對象中,如此一來局部變量就變成了對象內(nèi)的字段。然后你可以在同一個(gè)對象中將這個(gè)大型函數(shù)分解為多個(gè)小型函數(shù)。
方法參數(shù)比較多時(shí),將參數(shù)封裝為參數(shù)對象
任何有返回值的方法,都不應(yīng)該有副作用
臨時(shí)變量僅使用一次或者取值邏輯成本很低的情況下
將復(fù)雜表達(dá)式(或其中一部分)的結(jié)果放進(jìn)一個(gè)臨時(shí)變量,以此變量名稱來解釋表達(dá)式用途
把復(fù)雜的條件表達(dá)式拆分成多個(gè)條件表達(dá)式,減少嵌套。嵌套了好幾層的if - then-else語句,轉(zhuǎn)換為多個(gè)if語句
當(dāng)出現(xiàn)大量類型檢查和判斷時(shí),if else(或switch)語句的體積會(huì)比較臃腫,這無疑降低了代碼的可讀性。 另外,if else(或switch)本身就是一個(gè)“變化點(diǎn)”,當(dāng)需要擴(kuò)展新的類型時(shí),我們不得不追加if else(或switch)語句塊,以及相應(yīng)的邏輯,這無疑降低了程序的可擴(kuò)展性,也違反了面向?qū)ο蟮拈_閉原則。
非正常業(yè)務(wù)狀態(tài)的處理,使用拋出異常的方式代替返回錯(cuò)誤碼
某一段代碼需要對程序狀態(tài)做出某種假設(shè),以斷言明確表現(xiàn)這種假設(shè)。
當(dāng)使用一個(gè)方法返回的對象時(shí),而這個(gè)對象可能為空,這個(gè)時(shí)候需要對這個(gè)對象進(jìn)行操作前,需要進(jìn)行判空,否則就會(huì)報(bào)空指針。當(dāng)這種判斷頻繁的出現(xiàn)在各處代碼之中,就會(huì)影響代碼的美觀程度和可讀性,甚至增加Bug的幾率。
空引用的問題在Java中無法避免,但可以通過代碼編程技巧(引入空對象)來改善這一問題。
根據(jù)單一職責(zé)原則,一個(gè)類應(yīng)該有明確的責(zé)任邊界。但在實(shí)際工作中,類會(huì)不斷的擴(kuò)展。當(dāng)給某個(gè)類添加一項(xiàng)新責(zé)任時(shí),你會(huì)覺得不值得分離出一個(gè)單獨(dú)的類。于是,隨著責(zé)任不斷增加,這個(gè)類包含了大量的數(shù)據(jù)和函數(shù),邏輯復(fù)雜不易理解。
此時(shí)你需要考慮將哪些部分分離到一個(gè)單獨(dú)的類中,可以依據(jù)高內(nèi)聚低耦合的原則。如果某些數(shù)據(jù)和方法總是一起出現(xiàn),或者某些數(shù)據(jù)經(jīng)常同時(shí)變化,這就表明它們應(yīng)該放到一個(gè)類中。另一種信號(hào)是類的子類化方式:如果你發(fā)現(xiàn)子類化只影響類的部分特性,或者類的特性需要以不同方式來子類化,這就意味著你需要分解原來的類。
繼承使實(shí)現(xiàn)代碼重用的有力手段,但這并非總是完成這項(xiàng)工作的最佳工具,使用不當(dāng)會(huì)導(dǎo)致軟件變得很脆弱。與方法調(diào)用不同的是,繼承打破了封裝性。子類依賴于其父類中特定功能的實(shí)現(xiàn)細(xì)節(jié),如果父類的實(shí)現(xiàn)隨著發(fā)行版本的不同而變化,子類可能會(huì)遭到破壞,即使他的代碼完全沒有改變。
舉例說明,假設(shè)有一個(gè)程序使用HashSet,為了調(diào)優(yōu)該程序的性能,需要統(tǒng)計(jì)HashSet自從它創(chuàng)建以來添加了多少個(gè)元素。為了提供該功能,我們編寫一個(gè)HashSet的變體。
通過在新的類中增加一個(gè)私有域,它引用現(xiàn)有類的一個(gè)實(shí)例,這種設(shè)計(jì)被稱為組合,因?yàn)楝F(xiàn)有的類變成了新類的一個(gè)組件。這樣得到的類將會(huì)非常穩(wěn)固,它不依賴現(xiàn)有類的實(shí)現(xiàn)細(xì)節(jié)。即使現(xiàn)有的類添加了新的方法,也不會(huì)影響新的類。許多設(shè)計(jì)模式使用就是這種套路,比如代理模式、裝飾者模式
繼承與組合如何取舍
Java提供了兩種機(jī)制,可以用來定義允許多個(gè)實(shí)現(xiàn)的類型:接口和抽象類。自從Java8為接口增加缺省方法(default method),這兩種機(jī)制都允許為實(shí)例方法提供實(shí)現(xiàn)。主要區(qū)別在于,為了實(shí)現(xiàn)由抽象類定義的類型,類必須稱為抽象類的一個(gè)子類。因?yàn)镴ava只允許單繼承,所以用抽象類作為類型定義受到了限制。
接口相比于抽象類的優(yōu)勢:
接口雖然提供了缺省方法,但接口仍有有以下局限性:
接口缺省方法的設(shè)計(jì)目的和優(yōu)勢在于:
為了接口的演化
可以減少第三方工具類的創(chuàng)建
可以避免創(chuàng)建基類
由于接口的局限性和設(shè)計(jì)目的的不同,接口并不能完全替換抽象類。但是通過對接口提供一個(gè)抽象的骨架實(shí)現(xiàn)類,可以把接口和抽象類的優(yōu)點(diǎn)結(jié)合起來。 接口負(fù)責(zé)定義類型,或許還提供一些缺省方法,而骨架實(shí)現(xiàn)類則負(fù)責(zé)實(shí)現(xiàn)除基本類型接口方法之外,剩下的非基本類型接口方法。擴(kuò)展骨架實(shí)現(xiàn)占了實(shí)現(xiàn)接口之外的大部分工作。這就是模板方法(Template Method)設(shè)計(jì)模式。
Image [5].png
接口Protocol:定義了RPC協(xié)議層兩個(gè)主要的方法,export暴露服務(wù)和refer引用服務(wù)
抽象類AbstractProtocol:封裝了暴露服務(wù)之后的Exporter和引用服務(wù)之后的Invoker實(shí)例,并實(shí)現(xiàn)了服務(wù)銷毀的邏輯
具體實(shí)現(xiàn)類XxxProtocol:實(shí)現(xiàn)export暴露服務(wù)和refer引用服務(wù)具體邏輯
由于為了保持Java代碼的兼容性,支持和原生態(tài)類型轉(zhuǎn)換,并使用擦除機(jī)制實(shí)現(xiàn)的泛型。但是使用原生態(tài)類型就會(huì)失去泛型的優(yōu)勢,會(huì)受到編譯器警告。
每一條警告都表示可能在運(yùn)行時(shí)拋出ClassCastException異常。要盡最大的努力去消除這些警告。如果無法消除但是可以證明引起警告的代碼是安全的,就可以在盡可能小的范圍中,使用@SuppressWarnings("unchecked")注解來禁止警告,但是要把禁止的原因記錄下來。
參數(shù)化類型不支持協(xié)變的,即對于任何兩個(gè)不同的類型Type1和Type2而言,List既不是List的子類型,也不是它的超類。為了解決這個(gè)問題,提高靈活性,Java提供了一種特殊的參數(shù)化類型,稱作有限制的通配符類型,即List? extends E和List? super E。使用原則是producer-extends,consumer-super(PECS)。如果即是生產(chǎn)者,又是消費(fèi)者,就沒有必要使用通配符了。
還有一種特殊的無限制通配符List?,表示某種類型但不確定。常用作泛型的引用,不可向其添加除Null以外的任何對象。
嵌套類(nested class)是指定義在另一個(gè)類的內(nèi)部的類。 嵌套類存在的目的只是為了它的外部類提供服務(wù),如果其他的環(huán)境也會(huì)用到的話,應(yīng)該成為一個(gè)頂層類(top-level class)。 嵌套類有四種:靜態(tài)成員類(static member class)、非靜態(tài)成員類(nonstatic member class)、匿名類(anonymous class)和 局部類(local class)。除了第一種之外,其他三種都稱為內(nèi)部類(inner class)。
總而言之,這四種嵌套類都有自己的用途。假設(shè)這個(gè)嵌套類屬于一個(gè)方法的內(nèi)部,如果只需要在一個(gè)地方創(chuàng)建實(shí)例,并且已經(jīng)有了一個(gè)預(yù)置的類型可以說明這個(gè)類的特征,就要把它做成匿名類。如果一個(gè)嵌套類需要在單個(gè)方法之外仍然可見,或者它太長了,不適合放在方法內(nèi)部,就應(yīng)該使用成員類。如果成員類的每個(gè)實(shí)例都需要一個(gè)指向其外圍實(shí)例的引用,就要把成員類做成非靜態(tài)的,否則就做成靜態(tài)的。
通過對常見場景的代碼邏輯進(jìn)行抽象封裝,形成相應(yīng)的模板工具類,可以大大減少重復(fù)代碼,專注于業(yè)務(wù)邏輯,提高代碼質(zhì)量。
面向?qū)ο缶幊滔鄬τ诿嫦蜻^程,多了實(shí)例化這一步,而對象的創(chuàng)建必須要指定具體類型。我們常見的做法是“哪里用到,就在哪里創(chuàng)建”,使用實(shí)例和創(chuàng)建實(shí)例的是同一段代碼。這似乎使代碼更具有可讀性,但是某些情況下造成了不必要的耦合。
對于頂層的(非嵌套的)類和接口,只有兩種的訪問級(jí)別:包級(jí)私有的(沒有public修飾)和公有的(public修飾)。
對于成員(實(shí)例/域、方法、嵌套類和嵌套接口)由四種的訪問級(jí)別,可訪問性如下遞增:
正確地使用這些修飾符對于實(shí)現(xiàn)信息隱藏是非常關(guān)鍵的,原則就是:盡可能地使每個(gè)類和成員不被外界訪問(私有或包級(jí)私有)。這樣好處就是在以后的發(fā)行版本中,可以對它進(jìn)行修改、替換或者刪除,而無須擔(dān)心會(huì)影響現(xiàn)有的客戶端程序。
不可變類是指其實(shí)例不能被修改的類。每個(gè)實(shí)例中包含的所有信息都必須在創(chuàng)建該實(shí)例時(shí)提供,并在對象的整個(gè)生命周期內(nèi)固定不變。不可變類好處就是簡單易用、線程安全、可自由共享而不容易出錯(cuò)。Java平臺(tái)類庫中包含許多不可變的類,比如String、基本類型包裝類、BigDecimal等。
為了使類成為不可變,要遵循下面五條規(guī)則:
可變性最小化的一些建議:
TDD的最終目標(biāo)是整潔可用的代碼(clean code that works)。大多數(shù)的開發(fā)者大部分時(shí)間無法得到整潔可用的代碼。辦法是分而治之。首先解決目標(biāo)中的“可用”問題,然后再解決“代碼的整潔”問題。這與體系結(jié)構(gòu)驅(qū)動(dòng)(architecture-driven)的開發(fā)相反。
采用TDD另一個(gè)好處就是讓我們擁有一套伴隨代碼產(chǎn)生的詳盡的自動(dòng)化測試集。將來無論出于任何原因(需求、重構(gòu)、性能改進(jìn))需要對代碼進(jìn)行維護(hù)時(shí),在這套測試集的驅(qū)動(dòng)下工作,我們代碼將會(huì)一直是健壯的。
Image [6].png
添加一個(gè)測試 - 運(yùn)行所有測試并檢查測試結(jié)果 - 編寫代碼以通過測試 - 運(yùn)行所有測試且全部通過 - 重構(gòu)代碼,以消除重復(fù)設(shè)計(jì),優(yōu)化設(shè)計(jì)結(jié)構(gòu)
作者:VectorJin
對于每個(gè)編碼人員來說,避免重復(fù)代碼可能是大家都想做的。對于有一定經(jīng)驗(yàn)(對基本的OO原則有一定經(jīng)驗(yàn))的開發(fā)人員來說,大部分情況下都能比較自然地避免重復(fù)代碼的問題,寫代碼的時(shí)候,感覺有邏輯重復(fù)的情況,會(huì)很自然的憑感覺經(jīng)驗(yàn)做相應(yīng)的處理和復(fù)用。以下是個(gè)人經(jīng)驗(yàn),供新手參考。 既然我們在用Java之類的面向?qū)ο蟮恼Z言編碼,那么重復(fù)代碼可以大致分為如下兩種情況: 1、類型體系之內(nèi)(父類型和子類型、子類型之間)存在重復(fù)邏輯代碼 2、類型體系之外的重復(fù)代碼 【類型體系內(nèi)的重復(fù)代碼處理】 1、如果重復(fù)代碼屬于類型本身操作(即應(yīng)該是以實(shí)例方法存在),則很自然的應(yīng)用重構(gòu)技巧,公共代碼往上走。如果Sub Type之間有這種重復(fù)代碼,把重復(fù)代碼遷移到DefaultAdatper中。 2、如果重復(fù)代碼不屬于類型本身操作(即應(yīng)該是以靜態(tài)方法存在),則需要判斷一下這種靜態(tài)代碼的功能使用范圍: A、如果是非常全局性的,例如有關(guān)java流的輔助操作,則應(yīng)該果斷的抽取出來,封裝到一個(gè)Utility工具類中,例如可以叫做IOUtil。把這個(gè)Utility類放置到非常底層模塊中,這樣上層很多功能模塊中都可以使用,否則可能會(huì)導(dǎo)致上層多個(gè)模塊中都有類似IOUtil的類,又是重復(fù)代碼。1publicclassIOUtil{2/**3 *工具類,不需要產(chǎn)生實(shí)例。但是也不需要應(yīng)用單態(tài)!??!4*/5privateIOUtil(){}67publicstaticInputStreambuildInputSteam(Filefile){//}89//其他公共靜態(tài)操作10} B、如果這種靜態(tài)操作只對本類型體系有意義,則有兩種常用的處理方法:第一種是把這種靜態(tài)方法遷移到基類DefaultAdapter中,但是不要在DefaultAdapter中放置過多的類似靜態(tài)方法;第二種是把這種靜態(tài)方法封裝到一個(gè)helper助手類中,例如MyTypeHelper,其中放置了MyType類型體系中需要使用的一些靜態(tài)方法。如果第一種DefaultAdapter中堆放了較多的靜態(tài)方法,則可以用helper助手類的方式。1publicclassMyTypeHelper{2/**3 *助手類,不需要產(chǎn)生實(shí)例。但是也不需要應(yīng)用單態(tài)?。?!4*/5privateMyTypeHelper(){}67publicstaticbooleanvalidateParamer(Objectparamer){//}89//其他公共靜態(tài)操作10} 這個(gè)helper一般需要和接口、默認(rèn)適配類一起暴露,便于擴(kuò)展子類型使用。示意圖如下: 【類型體系之外的重復(fù)代碼處理】 類型體系之外的重復(fù)代碼處理相對就很簡單了,根據(jù)重復(fù)代碼功能適用范圍,封裝到對應(yīng)的Util類或者Helper類中。這里就不細(xì)講了~_~ 【有關(guān)公用代碼的幾個(gè)概念】 個(gè)人意見,僅供參考。 助手類(Helper class) :我覺得首先這個(gè)類產(chǎn)生的目的是為特定模塊或者特定功能服務(wù)的(助手嗎~_~),不是全局的。而且完全可以隱藏在特定模塊內(nèi)部,很多時(shí)候不需要暴露。Helper類的命名要有針對性,不能搞成一個(gè)麻辣燙,里面的靜態(tài)操作既為這種功能服務(wù),又為那種功能服務(wù),盡量做個(gè)忠臣,不要同時(shí)當(dāng)多個(gè)主子的助手。 工具類(Utility class) :一般是全局的,往往有一定普世價(jià)值,也就是說往往是全局通用的。 例如你在做一個(gè)模塊,這個(gè)模塊功能是處理表單,則關(guān)于處理表單的一些公用靜態(tài)操作就應(yīng)該放置到該模塊的一個(gè)助手類中,名稱類似于FormProcesserHelper。再有一個(gè)導(dǎo)出報(bào)表的功能,則對應(yīng)的助手類可以稱之為ExportReportHelper,建議這兩個(gè)helper不要混在一起。有人可能會(huì)說,這樣會(huì)不會(huì)導(dǎo)致大量的助手類呢?這邊有個(gè)粒度把握的問題(經(jīng)驗(yàn)會(huì)發(fā)生作用~_~),但是只要是助手類命名規(guī)范,則一個(gè)助手類的名字就基本上可以告訴用戶你提供什么樣的服務(wù)了。 假如你現(xiàn)在處理的是有關(guān)IO操作的重復(fù)代碼,則需要遷移到全局的工具類中,因?yàn)檫@樣的操作往往適應(yīng)于全局的。 Facade class(門面類) :這個(gè)乍看起來和助手類有點(diǎn)像,往往是綁定于特定模塊。但是,要搞清楚,門面類是用來封裝子系統(tǒng)的,代理對模塊常用核心功能的訪問的,針對用戶需要的常用場景提供一些輔助操作,幫助用戶更好的使用此模塊的主要功能。 面向客戶端或者其他子系統(tǒng)或模塊的,不是用來處理對應(yīng)模塊中重復(fù)代碼的 !?。∮嘘P(guān)詳細(xì)信息,請參加Facade設(shè)計(jì)模式的文檔。 【注意】Helper class、Utility class、Facade class一般都不需要生實(shí)例,暴露的都是靜態(tài)操作,更不需要誤寫成單態(tài),別濫用單態(tài)!??!后記:: 關(guān)于重復(fù)代碼的處理,個(gè)人以為既需要技巧(別人總結(jié)出來的技巧),更需要經(jīng)驗(yàn)(經(jīng)驗(yàn)往往給你感覺,跟著感覺走一般就不會(huì)太離譜~_~)。 希望對開發(fā)新手有作用~_~
你只需要考慮兩點(diǎn)進(jìn)行比較。
第一點(diǎn):考慮用戶ID,第二點(diǎn):考慮時(shí)間
當(dāng)你讀取一條log信息的時(shí)候,取出用戶ID和時(shí)間,
我不清楚你是實(shí)時(shí)的在執(zhí)行往DB里面插入還是過一點(diǎn)時(shí)間整理,
如果是實(shí)時(shí)插入,那么你取出這個(gè)log信息的時(shí)候,就需要去現(xiàn)在的數(shù)據(jù)庫里面進(jìn)行匹配
帶入用戶ID,和時(shí)間,時(shí)間就以小時(shí)計(jì)算,如:2014-11-18 17
如果在數(shù)據(jù)庫查詢出了這條數(shù)據(jù),那么跳出,如果沒有查詢出結(jié)果,那么新增。
第二種情況,如果你是隔一段時(shí)間執(zhí)行一次,那么你就只需要新建一個(gè)list集合,
然后用取出的log的集合循環(huán)和新的list數(shù)據(jù)進(jìn)行匹配,如果遇到有的就跳出,如果在新的list集合里面沒有的
那么就添加到新的list集合里面。
寫的有點(diǎn)亂,我這里不建議你用list,這樣匹配的時(shí)候循環(huán)工作量非常大,建議使用hashmap,鍵值對處理起來方便,
以用戶ID為key 方便處理。