設計模式(五)享元模式

版權聲明:轉載必須註明本文轉自曉_晨的博客:http://blog.csdn.net/niunai112

目錄

導航

設計模式之六大設計原則
設計模式(一)單例模式
設計模式(二)工廠模式
設計模式(三)策略模式
設計模式(四)適配器模式
設計模式(五)享元模式
設計模式(六)建造者模式
設計模式(七)原型模式
設計模式(八)橋接模式
設計模式(九)外觀模式
設計模式(十)組合模式
設計模式(十一)裝飾器模式
設計模式(十二)代理模式
設計模式(十三)迭代器模式
設計模式(十四)觀察者模式
設計模式(十五)中介者模式
設計模式(十六)命令模式
設計模式(十七)狀態模式
設計模式(十八)訪問者模式
設計模式(十九)責任鏈模式
設計模式(二十)解釋器模式
設計模式(二十一)備忘錄模式
設計模式(二十二)模板模式
設計模式總結篇(爲什麼要學習設計模式,學習設計模式的好處)

前言

今天LZ來給大夥介紹下享元模式,這個設計模式主要用於減少創建對象的數量,以減少內存佔用和提高性能。在JAVA中也有很廣泛的使用,比如Integer的緩存機制,在加載的時候就已經爲我們初始化好了-128 到 +127的實例,放在了緩存中,當我們要使用這裏面的數時,就會直接去緩存中拿對象,而不用重新實例化。這裏考慮了使用的程度,以及緩存大小給內存帶來的壓力,只實例化了-128到+127,當然你也可以通過
-Djava.lang.Integer.IntegerCache.high來修改來適應你係統的需求。

這裏扯遠了,LZ繼續介紹享元模式,模式最大的核心在於共享共同使用的對象。LZ這裏以自己的理解來給大家介紹以下享元模式

單純享元模式

當我們玩網遊的時候,一般新手會送一把木劍。然後木劍又是非常容易得到的,所以揹包裏會有很多把木劍,這個時候,假設你的揹包非常大,那每把木劍都實例一個木劍對象的話,你的內存有很大一部分都是在浪費,因爲存了重複的東西。但假如我們把木劍的屬性分開來,把不變的東西通過緩存共享(比如劍的攻擊速度,劍的材料,劍的攻擊力),只實例化變的東西(劍的耐久度),那就大大減少了內存的壓力。

/***
 *
 *@Author ChenjunWang
 *@Description:
 *@Date: Created in 18:33 2018/3/18
 *@Modified By:
 *
 */
abstract class Sword {
    private int aggressivity;
    private String speed;
    private String material;

    Sword(int aggressivity, String speed, String material){
        this.aggressivity = aggressivity;
        this.speed = speed;
        this.material = material;
    }

    public int attack(int Durability) {

        if (Durability>50)
            return this.getAggressivity();
        else if (Durability > 0 )
            return this.getAggressivity() / 2;
        return 0;
    }

    public int getAggressivity() {
        return aggressivity;
    }

    public String getSpeed() {
        return speed;
    }

    public String getMaterial() {
        return material;
    }
}

/***
 *
 *@Author ChenjunWang
 *@Description:
 *@Date: Created in 18:39 2018/3/18
 *@Modified By:
 *
 */
public class WoodSword extends Sword {

    public WoodSword(int aggressivity, String speed, String material) {
        super(aggressivity, speed, material);

    }


}


/***
 *
 *@Author ChenjunWang
 *@Description:
 *@Date: Created in 18:59 2018/3/18
 *@Modified By:
 *
 */
public class IronSword extends Sword {

    IronSword(int aggressivity, String speed, String material) {
        super(aggressivity, speed, material);
    }
}

/***
 *
 *@Author ChenjunWang
 *@Description:
 *@Date: Created in 18:48 2018/3/18
 *@Modified By:
 *
 */
public class SwordFactory {
    private static Map<String,Sword> map = new HashMap<>();

    static Sword getSword(String s){

        Sword sword = map.get(s);
        if (sword != null)
            return sword;

        if (s.equals("wood"))
            sword = new WoodSword(10,"快","木頭");
        else if (s.equals("iron"))
            sword = new IronSword(50,"較快","鐵");

        if (sword == null)
            return null;
        map.put(s,sword);
        return sword;

    }

}

/***
 *
 *@Author ChenjunWang
 *@Description:
 *@Date: Created in 18:47 2018/3/18
 *@Modified By:
 *
 */
public class Test {
    public static void main(String[] args) {
        Sword woodSword = SwordFactory.getSword("wood");
        System.out.println("耐久度爲100時,實際攻擊力爲:" + woodSword.attack(100));

        Sword woodSword2 = SwordFactory.getSword("wood");
        System.out.println("耐久度爲50時,實際攻擊力爲:" + woodSword2.attack(50));

        System.out.println("woodSword 和 woodSword2 是否是同一個對象?" + (woodSword == woodSword2));
    }
}

運行結果如下:
------------------------------------------------------
耐久度爲100時,實際攻擊力爲:10
耐久度爲50時,實際攻擊力爲:5
woodSword 和 woodSword2 是否是同一個對象?true


UML圖
pure

在這裏攻擊力,材料和攻速屬於內蘊,創建後就不可修改了,而耐久度屬於外韻,可以影響武器最終的攻擊力。單純享元就是這樣,其實可以理解爲用一個工廠管理單例的模式,單例用map來保存,然後工廠根據需要給出相應的實例。可能這個網遊的例子不是很好,因爲揹包有限,但是讓我們假設揹包是無限的,我們揹包每多一把木劍,就節省了不少內存空間,這樣子來想,是不是給我們的內存減少了很大的負擔呢。

複合享元模式

有的時候需要組合一些享元,然後通過一個組合類來共同管理


/***
 *
 *@Author ChenjunWang
 *@Description:
 *@Date: Created in 19:36 2018/3/18
 *@Modified By:
 *
 */
public class CompositeSword extends Sword {
    private List<Sword> swordList = new LinkedList<>();
    public CompositeSword(){
        super();

    }
    public void add(Sword sword){
        swordList.add(sword);
    }

    public void attack(List<Integer> Durability) {

        for (int i = 0; i < swordList.size(); i++){
            System.out.println(swordList.get(i).getMaterial() + swordList.get(i).attack(Durability.get(i)));
        }
    }
}

/***
 *
 *@Author ChenjunWang
 *@Description:
 *@Date: Created in 19:36 2018/3/18
 *@Modified By:
 *
 */
public class CompositeSword extends Sword {
    private List<Sword> swordList = new LinkedList<>();
    public CompositeSword(){
        super();

    }
    public void add(Sword sword){
        swordList.add(sword);
    }

    public void attack(List<Integer> Durability) {

        for (int i = 0; i < swordList.size(); i++){
            System.out.println("耐久度爲"+ Durability.get(i) + "實際攻擊力爲:" + swordList.get(i).attack(Durability.get(i)));
        }
    }
}



/***
 *
 *@Author ChenjunWang
 *@Description:
 *@Date: Created in 18:47 2018/3/18
 *@Modified By:
 *
 */
public class Test {
    public static void main(String[] args) {
        Sword woodSword = SwordFactory.getSword("wood");
        System.out.println("耐久度爲100時,實際攻擊力爲:" + woodSword.attack(100));

        Sword woodSword2 = SwordFactory.getSword("wood");
        System.out.println("耐久度爲50時,實際攻擊力爲:" + woodSword2.attack(50));

        System.out.println("woodSword 和 woodSword2 是否是同一個對象?" + (woodSword == woodSword2));

        List<String> list = new ArrayList<>();
        list.add("wood");
        list.add("wood");
        CompositeSword composite = SwordFactory.getComposite(list);
        List<Integer> d = new ArrayList<>();
        d.add(100);
        d.add(50);
        composite.attack(d);

    }
}

運行結果如下
------------------------------
耐久度爲100時,實際攻擊力爲:10
耐久度爲50時,實際攻擊力爲:5
woodSword 和 woodSword2 是否是同一個對象?true
耐久度爲100實際攻擊力爲:10
耐久度爲50實際攻擊力爲:5

URL圖
composite
這裏LZ符合類選擇用List,因爲LZ把這個理解成雙手都能持武器(拿2把劍),可以爲2把木劍,然後最後生成的對象,CompositeSword裏面list的Sword對象是共享的,但生成出來的CompositeSword每個都是不一樣的。然後每把劍都有自己的耐久度,我們可以通過list傳入耐久度,然後在CompositeSword裏遍歷,依次傳入耐久度調用attack。

總結

1、享元模式適用環境

  
  (1)一個系統有大量相同或者相似的對象,由於這類對象的大量使用,造成內存的大量耗費;
  (2)對象的大部分狀態都可以外部化,可以將這些外部狀態傳入對象中(細粒度對象);
  (3)使用享元模式需要維護一個存儲享元對象的享元池,而這需要耗費資源,因此,應當在多次重複使用享元對象時才值得使用享元模式。

2、享元模式的優點

  (1)它可以極大減少內存中對象的數量,使得相同對象或相似對象在內存中只保存一份;
  (2)享元模式的外部狀態相對獨立,而且不會影響其內部狀態,從而使得享元對象可以在不同的環境中被共享。

3、享元模式的缺點

  (1)享元模式使得系統更加複雜,需要分離出內部狀態和外部狀態,這使得程序的邏輯複雜化;
  (2)爲了使對象可以共享,享元模式需要將享元對象的狀態外部化,而讀取外部狀態使得運行時間變長。

Git地址

本篇實例Github地址:https://github.com/stackisok/Design-Pattern/tree/master/src/flyweight

回到最上方


有什麼不懂或者不對的地方,歡迎留言。
喜歡LZ文章的小夥伴們,可以關注一波,也可以留言,LZ會回你們的。
覺得寫得不錯的小夥伴,歡迎轉載,但請附上原文地址,謝謝^_^!

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