理解不變模式-Immutable Pattern<一>
題記:上邪?我欲與君相知?長命無絕衰?山無陵?江水為竭?冬雷陣陣?夏雨雪?天地合?乃敢與君絕 ? 從String說起: 用Java或C#時,如果一個字串是頻繁變化的,是不建議把該變數設為String類型的,而建議為StringBuilder,經過N次變化得到最終的字串後,再把StringBuilder轉化為String交給某個方法去處理。 不變模式會告訴我們,這是為什麼? 備註: 我學習設計模式時基本都參考閻巨集的《Java與模式》一書,該書中講述不變模式舉String這個例子時,若字串頻繁變化時建議使用StringBuffer,我原來用C#寫代碼時習慣用StringBuilder,.netframework只保證StringBuilder的公共Static成員是執行緒安全的。於是我去查看Java中StringBuilder的原碼發現該類的注釋中有這麼一句: Wherepossible,it isrecommended that this class be used in preference to StringBufferas it will befaster under most implementations. 請注意?“wherepossible”,的意思是:在單執行緒情況下。而StringBuffer是執行緒安全的。 ? 不變模式的概念: ? 一個物件如果可以改變自身的狀態,我們說它是可變的;如果一個物件的狀態自創建起便不可改變,我們說它是不可變的。 不變模式只涉及到一個類,這個類的內部狀態創建以後,在整個生命週期都不會發生變化,這樣的類叫做不變類,這種使用不變類的做法叫做不變模式。不變模式只有一個類,所以不需要類圖來表示。 備註:什麼是內部狀態? 在書上看,第一眼挺暈的,因為搞學術的都有這“毛病”,喜歡把簡單的東西說的很複雜,你看那些博士論文,還有一些很牛B的碩士論文就會發現這個問題。我只所以把“毛病”加引號是因為我不全盤否定這種做法,雖然他對初學者及搞應用的人來講會造成一定的障礙,但它對理論的發展卻很重要,因為我們理解這個概念以後,討論起來就會更加清晰,就像無論我們學什麼,講什麼第一步總是要先把概念講清楚,理解清楚。如果缺了這一步,費半天勁會發現不知道自己在幹什麼,這個太可怕了。 言歸正傳,所謂內部狀態,就是這個類的屬性,完了。就像WebService,一聽好神奇啊,你去看書,那理論一套一套的好幾章,說白了就是:基於Web的API,完了。 怎麼讓它不變: 使用不變類的做法就是不變模式,所謂不變類就是它的整個生命週期裡它的狀態就不會改變,那怎樣讓它的狀態(屬性)不會發生變化呢?當我們把概念講到這裡的時候,我想我們基本都會把它寫出來了:把屬性設為私有,只給Geter不給Setter就OK了。Yes!給個例子先: ? public?class?PartySchool{ ????private?String?appearance; ? ????public?StringgetAppearance() { ???????return?appearance; ????} ????public?PartySchool(Stringappearance) ????{ ???????this.appearance?= appearance; ????} } CodeIP-1 當用戶端調用的時候給予初始值: PartySchool ps =newPartySchool(“handsome”); 那麼在PartySchool的整個生命週期裡一直都handsome,是不可變的。 特殊情況: 我家養了一條狗叫毛毛,給毛毛建個類先: public?class?Dog{ ????private?String?name; ? ????public?StringgetName() { ???????return?name; ????} ? ????public?void?setName(String name) { ???????this.name?= name; ????} ????public?Dog(Stringname) ????{ ???????this.name?= name; ????} } CodeIP-2 顯然,我們家毛毛的名字是可以改的,比如我不叫它毛毛了給它取個英文名字叫Douglas。 順便把PartySchool這個類也修改下: public?class?PartySchool{ ????private?String?appearance; ????private?Dog?dog; ????public?StringgetAppearance() { ???????return?appearance; ????} ????public?DoggetDog() { ???????return?dog; ????} ? ????public?PartySchool(Stringappearance,Dog dog) ????{ ???????this.appearance?= appearance; ???????this.dog?=dog; ????} } CodeIP-3 我想看到這個類會隱隱有種不詳的預感,寫個測試驗證一下: public?static?void?main(String[] args) { ???????Dogdog =?new?Dog("maomao"); ???????PartySchoolps =?new?PartySchool("handsome",dog); ???????System.out.println(ps.getAppearance()); ???????System.out.println(ps.getDog().getName()); ???????System.out.println("-----------------Changed--------------------"); ???????dog.setName("Douglas"); ???????System.out.println(ps.getAppearance()); ???????System.out.println(ps.getDog().getName()); ????} CodeIP-4 悲劇的結果: handsome maomao -----------------Changed-------------------- handsome Douglas 悲劇發生了,因為不變類裡出現了可變的不和諧分子。如何把它和諧掉呢?偉大的程式師是不需要維穩經費的,我們只需要改掉一行代碼就OK了。 把PartySchool的構造函數改為: ????public?PartySchool(Stringappearance,Dog dog) ????{ ???????this.appearance?= appearance; ???????DogdogClone =?new?Dog(dog.getName()); ???????this.dog?=dogClone; ????} CodeIP-5 同樣的測試用例測試結果: handsome maomao -----------------Changed-------------------- handsome maomao 好!歌舞昇平,我家毛毛還叫毛毛。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- string – Scala中的条件隐式函数
- angularjs – 如何告诉gulp-connect打开index.html,无论URL
- twitter-bootstrap – Bootstrap无线电内联线路包装和堆叠单
- 如何使用vim中的鼠标选择一大块文本并将其粘贴到当前光标位
- 使用Scala ObservableSet Trait的示例
- vim – 打开该类型的文件时是否可以自动设置UTF16文件编码?
- Angular2全局变量可观察
- Angular Reactive Form - 填充表单模型
- twitter-bootstrap – 如何通过渲染显示带有DataTables的Bo
- angularjs - Error: [$resource:badcfg] Error in resource