題記:上邪 我欲與君相知 長命無絕衰 山無陵 江水為竭 冬雷陣陣 夏雨雪 天地合 乃敢與君絕
從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
好!歌舞昇平,我家毛毛還叫毛毛。