不變模式

一個對象的狀態在對象被創建後就不再變化,這就是所謂的不變(Immutable)模式。
一般來說,一個對象要麼是可變(Mutable Object)對象,要麼是不可(Immutable Object)變對象。一個可變對象的狀態可以改變,而一個不變對象的狀態不可以改變。不變模式的做法早在面向對象的編程中便得到應用。不變模式缺少改變自身狀態的行爲,因此它是關於行爲的,所以可以把它劃歸爲行爲模式。

不變模式的結構和實現
不變模式可增強對象的強壯性(robustness)。不變模式允許多個對象共享某一個對象,降低了對該對象進行併發訪問(Concurrent Access)時的同步化開銷。如果需要修改一個不變對象的狀態,那麼就需要建立一個新的同類型的對象,並在創建時將這個新的狀態存儲在新的對象裏。
不變模式只涉及到一個類。一個類的內部狀態創建後,在整個生命期間都不會發生變化時,這樣的類稱作不變類。這種使用不變類的做法叫做不變模式。不變模式有兩種類型:一種是弱不變模式;另一種是強不變模式。
弱不變模式
一個類的實例的狀態是不可變化的;但是這個類的子類的實例具有可能會變化的狀態。這樣的類符合弱不變模式的定義。要實現弱不變模式,必須滿足下面的條件:
(1)所考慮的對象沒有任何方法會修改對象的狀態;這樣一來,當對象的構造子將對象的狀態初始化之後,對象的狀態便不在改變。
(2)所有的屬性都應當是私有的。不要聲明任何公開的屬性,以防客戶端對象直接修改任何的內部狀態。
(3)這個對象所引用到的其他對象如果是可變對象的話,必須設法限制外界對這些可變對象的訪問,以防止外界修改這些對象。如果可能, 應當儘量在不變對象內部初始化這些被引用到的對象,而不要在客戶端初始化,然後再傳入到不變對象內部來。如果某個可變對象必須在客戶端初始化,然後再傳入到不變對象內部的話,就應當考慮在不變對象初始化的時候,將這個可變對象複製一份,而不要使用原來的拷貝。
弱不變模式的缺點:
第一、一個弱不變對象的子對象可以是可變對象,或者一個弱不變對象的子對象可能是可變的。
第二、這個可變的子對象可能可以修改父對象的狀態,從而可能會允許外界修改父對象的狀態;這是一個顯著的缺點。

強不變模式
一個類的實例的狀態不會改變,同時它的子類的實例也具有不可變化的狀態。這樣的類符合強不變模式。要實現強不變模式,一個類必須滿足弱不變模式所要求的所有條件外,還必須滿足下面的條件之一:
第一、所考慮的類的所有方法都必須是final;這樣這個類的子類不能夠置換掉此類的方法;
第二、這個類本身就是final的,那麼這個類就不可能有子類,從而也就不可能有子類被修改的問題。

“不變”和“只讀”的區別
“不變(Immutable)”和“只讀(Read Only)”是不同的。但一個變量是隻讀時,變量的值不能直接改變,但是可以在其他變量發生改變的時候發生改變。
比如一個人的出生年月日是不變的屬性,而一個人的年齡便是隻讀的屬性,但年齡不是不變屬性,隨着時間的變化,一個人的年齡會隨之變化,而人的出生年月日則不會變化,這就是不變和只讀的區別。

                                                       不變模式在java語言中的應用
   不變模式在java語言中有很重要的作用,最著名的便是java.lang.String類。

String類
java中的String類是一個強不變類,在出現如下代碼時:
String tmpType =”type”;
String mType =”type”;
java虛擬機其實只會創建一個這樣的字符串的實例,而這兩個String對象都共享這一個值。
如果程序所處理的字符串有頻繁的內容變化時,就不宜用String類型,而應當考慮使用StringBuffer類型,如果需要對字符串做大量的循環查詢時,也不宜使用Stringe類型,應當考慮使用byte或char數組。

封裝類

 String實際上是一個封裝類(Wrapper Class),因爲它包裝了一個char的數組。在java語言中,java.lang庫中還有其他的封裝類,如Integer、Float、Double、Byte、Long、Short、Boolean和Character。爲什麼需要這些封裝類?


  一個Long類型的對象所起的作用在於它把一個long原始類型的值包裝在一個對象裏,有了封裝類,就可以把原始數據類型包裝起來作爲對象處理。這些封裝類都是強不變類,因爲這些類都是final的,而且對象被創建時,它們的狀態就確定了。



                                            不變模式的優點和缺點

 不變模式有很明顯的優點:

(1)因爲不能修改一個不變對象的狀態,所以可以避免由此引起的不必要的程序錯誤;一個不變的對象要比一個可變的對象更加容易維護。

(2)因爲沒有任何一個線程能夠修改不變對象的內部狀態,一個不變對象自動就是線程安全的,這樣可以省掉處理同步化的開銷。一個不變對象可以自由地被不同的客戶端共享。不變模式唯一的缺點就是:一旦需要修改一個不變對象的狀態,就只好創建一個新的同類對象。在需要頻繁修改不變對象的環境裏,會有大量的不變對象作爲中間結果被創建出來,再被java中的垃圾回收器收集走,這是一種資源上的浪費。

 在設計一個類的時候,應當慎重考慮其狀態是否有需要改變的可能性。除非其狀態有變化的必要,不然應當將它設計爲不變類。

不變模式與享元模式的關係

  享元模式以共享的方式支持大量的實例。享元模式中的享元對象可以是不變對象。實際上大多數享元對象是不變對象。

 但是必須指出的是,享元模式並不要求享元對象一定是不變對象。享元模式要求享元對象的狀態不隨環境的變化而變化,這是使享元對象可以共享的條件,當然如果享元對象成爲不變對象的話,也是能滿足享元模式要求的。

 享元模式對享元對象的要求是它的內蘊狀態與環境無關。這意味着享元對具有某個可變的狀態,但是隻要不影響享元對象的共享,也是允許的。

 不變模式對不變對象的約束較強,而享元模式對享元對象的約束較弱。只要系統允許,可以使用不變模式實現享元對象,但是享元對象不一定非是不變對象不可。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章