设计模式-享元模式
栗子
使用工廠方法,表現層通過工廠方法創建對象,再傳遞給業務層,持久層,最后保存到數據庫中。
報考信息
報考信息工廠,批量生產報考信息對象
public class SiginfoFactory{// 報名信息的對象工廠public static Signinfo getSigninfo(){return new Signinfo();} }最后書寫場景
public class Client{public static void main(String[] args){// 從工廠中獲得對象Signinfo signinfo = SigninfoFactory.getSigninfo();// 進行其他業務處理} }垃圾回收機制
jvm有垃圾回收機制,即自動內存管理。其中堆是所有線程都共享的,而棧是每個線程都各自擁有的。
程序有程序計數器,當線程超過cpu數量,或者cpu內核數量的時候,線程根據時間片輪詢搶奪cpu時間資源,即每個線程都需要一個獨立的程序計數器記錄正在執行的字節碼的指令地址。
虛擬機棧,虛擬機棧是java方法執行的內存模型,為線程私有,每個方法在執行的時候,會創建一個棧幀,這個棧幀保存著局部變量表,操作數棧,動態鏈接,方法出口,每個方法的調用,都代表著一個棧幀從入棧到出棧的過程。方法調用會入棧,方法返回會出棧
關于java堆,垃圾收集器的主要管理區域,即GC堆,java垃圾回收算法有引用計數法,通過判斷對象的引用數量決定對象是否可以被回收,當引用為0的對象,可以被當做垃圾回收,當對象之間相互引用的時候,由于兩者引用計數都不為0,所以不能使用gc進行清除。
可達性分析算法,程序把引用關系看做一張圖,從節點往下搜索,當對象沒有任何引用鏈的時候,會證明不可達,此時進行回收
垃圾收集算法,對象先判斷是否可以進行回收,先標記再清除,從跟集合掃描,對存活對象標記,標記完成以后,對未標記的進行回收。復制算法。將可用內存分大小相等兩塊,這一塊用完,將存活的復制到另外一塊上,再把已經使用的內存空間一次清除掉。即,將堆空間分為兩塊,一塊為新生代,一塊為老年代,在進行回收的時候,會把存活的對象,復制到新生代中,將老年代清空。
內存泄露
使用HashMap,Vector等集合類的靜態使用容易出現內存泄露,因為這些靜態變量的生命周期和應用程序一致。
即各種資源的連接,網絡連接,IO連接沒有被close關閉,
更改
當并發數增多的時候,每個線程會創建對象,并發數越多,線程數越多,此時會造成內存的瘋狂占用,造成內存泄露。
解決:對象池。使用一個共享池來解決問題。
代碼如下
下面書寫帶對象池的工廠類
public class SigninfoFactory{// 池容器private static HashMap<String, Signinfo> pool = new hashMap<String, Signinfo>();// 對象工廠@Deprecated// 對原先代碼進行修改的時候,需要加上Deprecated,表明這個方法已經廢棄。不在建議使用,不建議刪除,因為如果有其他繼續使用這個方法的時候,將會導致出現不可預知的問題。用于向下兼容public static Signinfo(){return new Signinfo();}// 獲得對象public static Signinfo getSigninfo(String key){Signinfo result = null;// 當key值存在的時候,從對象池中獲得該對象。當key值不存在的時候,創建對象,并放入對象池中。if(!pool.containsKey(key)){result = new Signinfo4Pool(key);pool.put(key, result);}else{result = pool.get(key);}return result;}}最后書寫場景類
public class Client{public static void main(String[] args){// 初始化對象池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 singinfo = SignInfoFactory.getSignInfo("科目1地點1");} }總結
即,將共性的內容,提取出來,然后在新建一個子類,然后在子類中預留出外部訪問的。上方的栗子為key。然后在工廠模式中,String為key,value的值為key對應的對象池中創建的對象。
ps 在上方的栗子中id作為附屬的,即,對象的動態信息。池 + 工廠
通過新建一個對象池,該池內的對象有HashMap來進行保存,然后通過工廠,輸入key值,獲取到對象。
核心在于創建出業務需要的對象,然后在運行的時候,直接使用該對象。因為堆是所有線程所共享的。
線程安全
由于java中堆是所有線程所共享的,所以當共享池中的對象數不夠的時候,會出現線程安全的問題,即,多個線程,共同訪問一個對象,同時修改造成數據的錯誤。
即,在使用享元模式的時候,對象要盡可能的多,直到業務需求全部滿足。還要注意線程安全的問題,當一個線程
外部狀態/內部狀態
關于外部狀態和內部狀態,其中內部狀態不可更改,外部狀態可更改,但是多線程的時候會出現很嚴重的問題,即線程不安全,當多個線程共同訪問,操作外部狀態的時候,會出現線程不安全。至今不知道怎么解決。
繼續擴展
此時,新建一個類,用于保存key值,替代原先的String方式。
再寫static類型的里面保存的HashMap,用于保存當前池中的對象。
需要使用的時候,直接新將外部類,將內容set進入。
工廠內需要調用狀態類的方法,生成String和HashMap中的key進行對比。若已經生成,直接返回該對象,否則不返回該對象
總結
享元模式 = 工廠模式 + 池
總結
- 上一篇: Trustdata:映客直播站稳行业第一
- 下一篇: 设计模式之工厂模式(三)