享元模式

享元模式(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");
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章