Java-享元-設計模式(十一)
說明
概念:
享元模式用來儘可能減少記憶體使用量以及分享資訊給儘可能多的相似物件;它適合用於只是因重複而導致使用無法令人接受的大量記憶體的大量物件。通常物件中的部分狀態是可以分享。
兩個狀態:
內蘊狀態儲存在享元內部,不會隨環境的改變而有所不同,是可以共享的。
外蘊狀態是不可以共享的,它隨環境的改變而改變的,因此外蘊狀態是由客戶端來保持(因為環境的變化是由客戶端引起的)。
角色:
抽象享元角色:為具體享元角色規定了必須實現的方法,而外蘊狀態就是以引數的形式通過此方法傳入。在Java中可以由抽象類、介面來擔當。
具體享元角色:實現抽象角色規定的方法。如果存在內蘊狀態,就負責為內蘊狀態提供儲存空間。
客戶端角色:維護對所有享元物件的引用,而且還需要儲存對應的外蘊狀態。
程式碼
一個字元管理的小示例,先看示例,最後再結合上述定義做解釋。
抽象享元角色,字元
/**
* @author ctl
* @date 2021/1/22
*/
public interface Word {
void write(int x, int y);
}
具體享元角色,中文字元
/**
* @author ctl
* @date 2021/1/22
*/
public class ChineseWord implements Word {
private String str;
public ChineseWord(String str) {
this.str = str;
}
@Override
public void write(int x, int y) {
System.out.println("寫中文:" + str + ",座標[" + x + "," + y + "]");
}
}
享元工廠角色,管理字元物件
/**
* @author ctl
* @date 2021/1/22
*/
public class WordFactory {
private static Map<String, Word> map = new HashMap<>();
public static Word getWord(String str) {
Word word = map.get(str);
if (word == null) {
word = new ChineseWord(str);
map.put(str, word);
}
return word;
}
}
客戶端
/**
* @author ctl
* @date 2021/1/22
* 兩個word物件是同一個物件,但是座標不同
*/
public class FlyWeightMain {
public static void main(String[] args) {
Word test = WordFactory.getWord("測試");
Word test2 = WordFactory.getWord("測試");
test.write(1, 2);
test2.write(3, 4);
System.out.println(test == test2);
}
}
結果
可以看出兩個word物件的記憶體地址相同,沒有開闢新的記憶體,同時可以滿足外部控制座標不同的需求。
我們再來看一下兩個狀態和四個角色在上述示例中的體現。
內蘊狀態對應這個字元物件的寫方法中的型別,示例中是中文,是固定的,可共享的,外部不可變的。
外蘊狀態對應這個字元物件的座標,是不共享的,是外部可變的。
抽象享元角色對應Word介面,定義了寫方法。
具體享元角色對應中文字元類,實現類寫方法,並存儲了內蘊狀態。
享元工廠角色對應工廠類,達到了共享物件的目的。
客戶端角色對應測試類,可以傳入外蘊狀態。
總結
如果一個應用程式使用了大量的物件,而這些物件造成了很大的儲存開銷的時候就可以考慮是否可以使用享元模式。
例如,如果發現某個物件的生成了大量細粒度的例項,並且這些例項除了幾個引數外基本是相同的,如果把那些共享引數移到類外面,在方法呼叫時將他們傳遞進來,就可以通過共享大幅度單個例項的數目。
資料庫連線池中體現了享元模式的思想,使用同一目標的連線物件時,不會每次建立新的連線,而是從池中去取。