版權聲明:轉載必須註明本文轉自曉_晨的博客: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圖
在這裏攻擊力,材料和攻速屬於內蘊,創建後就不可修改了,而耐久度屬於外韻,可以影響武器最終的攻擊力。單純享元就是這樣,其實可以理解爲用一個工廠管理單例的模式,單例用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圖
這裏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會回你們的。
覺得寫得不錯的小夥伴,歡迎轉載,但請附上原文地址,謝謝^_^!