享元模式(Flyweight Pattern)是池技術的重要實現方式,其定義如下:Use sharing to
support large numbers of fine-grained objects efficiently.(使用共享對象可有效地支持大量的細
粒度的對象。)
享元模式的定義爲我們提出了兩個要求:細粒度的對象和共享對象。我們知道分配太多
的對象到應用程序中將有損程序的性能,同時還容易造成內存溢出,那怎麼避免呢?就是享
元模式提到的共享技術。我們先來了解一下對象的內部狀態和外部狀態。
要求細粒度對象,那麼不可避免地使得對象數量多且性質相近,那我們就將這些對象的
信息分爲兩個部分:內部狀態(intrinsic)與外部狀態(extrinsic)。
● 內部狀態
內部狀態是對象可共享出來的信息,存儲在享元對象內部並且不會隨環境改變而改變,
如我們例子中的id、postAddress等,它們可以作爲一個對象的動態附加信息,不必直接儲存
在具體某個對象中,屬於可以共享的部分。
● 外部狀態
外部狀態是對象得以依賴的一個標記,是隨環境改變而改變的、不可以共享的狀態,如
我們例子中的考試科目+考試地點複合字符串,它是一批對象的統一標識,是唯一的一個索
引值。
● 內存泄漏
無意識的代碼缺陷,導致內存泄漏,JVM不能獲得連續的內存空間。
● 對象太多
代碼寫得很爛,產生的對象太多,內存被耗盡。現在的情況是沒有內存泄漏,那只有一
種原因——代碼太差把內存耗盡。
● 考試科目,選擇框。
● 考試地點,選擇框,根據科目不同,列表不同。
● 准考證郵寄地址,輸入框。
還有其他一堆信息,我們以這三者作爲代表來講解。信息填寫完畢後,點擊確認,報名
就結束了。簡單程序的業務邏輯也確實是這樣,爲什麼出現Crash情況呢?那肯定是和壓力
有關係!
我們先把這個過程的靜態類圖畫出來,如圖
很簡單的工廠方法模式,表現層通過工廠方法模式創建對象,然後傳遞給業務層和持久
層,最終保存到數據庫中,爲什麼要使用工廠方法模式而不用直接new一個對象呢?因爲是
在框架下編程,必須有一個對象工廠(ObjectFactory,Spring也有對象工廠)。
package FlyweightP; public class SignInfo { //報名人員的ID private String id; //考試地點 private String location; //考試科目 private String subject; //郵寄地址 private String postAddress; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getLocation() { return location; } public void setLocation(String location) { this.location = location; } public String getSubject() { return subject; } public void setSubject(String subject) { this.subject = subject; } public String getPostAddress() { return postAddress; } public void setPostAddress(String postAddress) { this.postAddress = postAddress; } }
package FlyweightP; public class SignInfoFactory { public static SignInfo getSignInfo(){ return new SignInfo(); } }
package FlyweightP; public class Client { public static void main(String[] args) { SignInfo signInfo = SignInfoFactory.getSignInfo(); } }
我們自己來設計一個共
享對象池,需要實現如下兩個功能。
● 容器定義
我們要定義一個池容器,在這個容器中容納哪些對象。
● 提供客戶端訪問的接口
我們要提供一個接口供客戶端訪問,池中有可用對象時,可以直接從池中獲得,否則建
立一個新的對象,並放置到池中。
package FlyweightP; public class SignInfoPool extends SignInfo { //定義一個對象池提取的key值 private String key; public SignInfoPool(String key){ this.key = key; } public String getKey() { return key; } public void setKey(String key) { this.key = key; } }
package FlyweightP; public class Client { public static void main(String[] args) { // SignInfo signInfo = SignInfoFactory.getSignInfo(); //初始化對象池 for(int i=0;i<4;i++){ String subject = "科目" + i; //初始化地址 for(int j=0;j<30;j++){ String key = subject + "考試地點"+j; SignInfoFactory.getSignInfo(key); } } SignInfo signInfo = SignInfoFactory.getSignInfo("科目1考試地點1"); } }