設計模式:享元模式
阿新 • • 發佈:2020-12-27
定義
享元模式(Flyweight Pattern)主要用於減少建立物件的數量,以減少記憶體佔用和提高效能。這種型別的設計模式屬於結構型模式,它提供了減少物件數量從而改善應用所需的物件結構的方式。
適用場景:
- 應用於系統底層開發。以解決系統性能問題
- 系統有大量相似物件,需要緩衝池場景
具體場景
享元模式主要包含三種角色:
- 抽象享元角色(IFlyweight):享元物件抽象基類或者介面,同時定義出物件的外部狀態和內部狀態的介面或實現。
- 具體享元角色:實現抽象享元角色,該角色的內部狀態處理應該與環境無關,不會出現一個操作改變內部狀態,同時改變外部狀態的情況。
- 享元工廠:負責管理享元物件池和建立享元物件。
以英雄聯盟兵線為例:有四種小兵,前排兵,後排兵,炮車,超級兵,每個兵種都有自己的顏色(忽略因時間變化等級升高的影響和大龍buff加持的影響等等),可以用享元模式簡單實現一下前排兵,後排兵的建立(跑車和超級兵省略)。
小兵介面
public interface Minion {
String getType();
String getColour();
default void attack(){
System.out.println(getColour()+"色方的"+getType()+"正在攻擊....");
}
}
近戰兵:
//近戰兵 public class MeleeMinion implements Minion{ private String colour; MeleeMinion(String colour) { this.colour = colour; } @Override public String getType() { return "近戰兵"; } @Override public String getColour() { return colour; } }
遠端兵:
//遠端兵 public class CasterMinion implements Minion{ private String colour; CasterMinion(String colour) { this.colour = colour; } @Override public String getType() { return "遠端兵"; } @Override public String getColour() { return this.colour; } }
享元工廠:
class MinionFactory {
private static Map<String, Minion> minionPool = new ConcurrentHashMap<>();
//因為內部狀態的不變性,所以快取起來作為主鍵
static Minion getMinion(String type, String colour){
Minion minion;
if("遠端兵".equals(type)){
if(!minionPool.containsKey(colour)){
minion = new CasterMinion(colour);
minionPool.put(colour,minion);
}
}else if("近戰兵".equals(type)){
if(!minionPool.containsKey(colour)){
minion = new MeleeMinion(colour);
minionPool.put(colour,minion);
}
}
minion = minionPool.get(colour);
return minion;
}
}
測試:
public class Test {
public static void main(String[] args) {
Minion minion = MinionFactory.getMinion("近戰兵", "藍");
minion.attack();
Minion minion2 = MinionFactory.getMinion("近戰兵", "藍");
minion2.attack();
System.out.println(minion == minion2);
Minion minion3 = MinionFactory.getMinion("遠端兵", "紅");
minion3.attack();
}
}
uml類圖:
Integer(Long)中的享元模式
先測試以下程式碼:
public static void main(String[] args) {
Integer a = 100;
Integer b = 100;
System.out.println(a==b);
Integer c = 200;
Integer d = 200;
System.out.println(c==d);
}
一個為true,一個為false???是不是意想不到。
打上斷點,除錯:
可以得出,a和b是同一個物件,c和d不是同一個物件,進入Integer原始碼,我們可以注意到這樣一段程式碼:
/**
* Returns an {@code Integer} instance representing the specified
* {@code int} value. If a new {@code Integer} instance is not
* required, this method should generally be used in preference to
* the constructor {@link #Integer(int)}, as this method is likely
* to yield significantly better space and time performance by
* caching frequently requested values.
*
* This method will always cache values in the range -128 to 127,
* inclusive, and may cache other values outside of this range.
*
* @param i an {@code int} value.
* @return an {@code Integer} instance representing {@code i}.
* @since 1.5
*/
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
Integer的valueOf方法:當值大於等於low或者小於等於high時會呼叫IntegerCache.cache()方法,否則直接new一個新的Integer,我們繼續看IntegerCache的原始碼:
實際上,jdk在Long類中也有這樣的處理。