詳解Java設(shè)計模式編程中的Flyweight享元模式的開發(fā)結(jié)構(gòu)
享元(Flyweight)模式:通過共享技術(shù)以便有效的支持大量細粒度的對象。
享元模式在閻宏的《java與模式》中分為單純享元模式和復(fù)合享元模式,復(fù)合模式的復(fù)合享元是不可以共享的,享元對象能做到共享的關(guān)鍵是區(qū)分內(nèi)蘊態(tài)(Internal State)和外蘊態(tài)( External State)。這兩個“蘊態(tài)”翻譯的太難懂,我不是說翻譯的不好,可能是我理解能力差,還是《Design Pattern Elements of Reusable Object-Oriented Software》的翻譯版《設(shè)計模式可復(fù)用面向?qū)ο筌浖幕A(chǔ)》一書總翻譯為內(nèi)部對象和外部對象,相對直白,對概念性的東西文學(xué)氣味太強了就覺得很別扭。這里的角色也采用《設(shè)計模式可復(fù)用面向?qū)ο筌浖幕A(chǔ)》的說法,不區(qū)分單純模式和復(fù)合模式,而是有一個UnSharedConcreteFlyweight(在《java與模式》里稱復(fù)合享元,指明復(fù)合享元不能共享),我們這里稱它不可以共享享元角色,這樣享元模式的角色有:
- 抽象享元(Flyweight)角色:是給實現(xiàn)享元提供的接口。
- 具體享元(ConcreteFlyweight)角色:實現(xiàn)抽象角色,此對象必須是共享的,所含的狀態(tài)必須是內(nèi)部狀態(tài)。
- 不共享享元(UnSharedConcreteFlyweight)角色:此對象不可共享,不是所有實現(xiàn)抽象享元接口的的對象都要共享,此對象通常將ConcreteFlyweight作為組成元素。
- 享元工廠(FlyweightFactory)角色:負責創(chuàng)建和管理享元角色,確保合理共享。
- 客戶端(Client)角色:維持一個Flyweight對象的引用,計算或存儲一個(多個)外部存儲狀態(tài)。
享元模式的類的機構(gòu)圖如下:
享元模式在java.lang.String設(shè)計上的使用,我們知道java中字符串始終保持共享一份,如下面代碼片段:
String m = "a"; String n = "a"; System.out.println(m==n);
這樣會輸出true,說明m和n指向了同一個實例,內(nèi)存中也只有一個"a"。這就是享元模式在String上的使用。
享元模式在文字編輯存貯過程中的使用,這里假定文章由行對象組成,行對象由若干個字符對象組成,但是如果每個字符都保存自己的對象,那么一篇文章成千上萬個字符對象,這樣嚴重消耗系統(tǒng)內(nèi)存,造成不可接受的運行時開銷,好的方法是利用享元模式,只保存ASCII字符編碼值,作為內(nèi)部不變的狀態(tài),對當個字符對象進行共享,而相對字符顏色、大小這樣的格式化數(shù)據(jù)作為外部狀態(tài),由客戶端維護,運行時由外部傳入即可。每個行作為不可共享享元對象,它是由享元對象(字符對象)組合而成的。
我們來看個簡單地享元模式的結(jié)構(gòu)的例子:
/** * 字母 */ public class Letter { private String name; public Letter(String name) { this.name = name; } public String getName() { return name; } }
/** * 一個產(chǎn)生字母對象的 享元工廠(單例工廠) */ public class LetterFactory { private Map<String, Letter> map; private static LetterFactory instance = new LetterFactory(); private LetterFactory() { map = new HashMap<String, Letter>(); } public static LetterFactory getInstance() { return instance; } public void add(Letter letter) { if (letter != null && !map.containsKey(letter.getName())) { map.put(letter.getName(), letter); } System.out.println("map.size====" + map.size()); } public Letter get(String name) { return map.get(name); } }
public class Test { public static void main(String[] args) { LetterFactory factory = LetterFactory.getInstance(); String word = "easiness"; addLetterByName(factory, word); getLetter(factory, word); } //添加字母對象 static void addLetterByName(LetterFactory factory, String word) { for (char c : word.toCharArray()) { factory.add(new Letter(c + "")); } } //輸出字母對象 static void getLetter(LetterFactory factory, String word) { for (char c : word.toCharArray()) { System.out.println(factory.get(c + "")); } } }
打?。?/p>
map.size====1 map.size====2 map.size====2 map.size====3 map.size====4 map.size====5 map.size====5 flyweight.Letter@3343c8b3 flyweight.Letter@272d7a10 flyweight.Letter@3343c8b3 flyweight.Letter@1aa8c488 flyweight.Letter@3dfeca64 flyweight.Letter@22998b08 flyweight.Letter@1aa8c488
相關(guān)文章
教你使用springSecurity+jwt實現(xiàn)互踢功能
JWT作為一個開放的標準( RFC 7519 ),定義了一種簡潔的,自包含的方法用于通信雙方之間以Json對象的形式安全的傳遞信息。接下來通過本文給大家介紹springSecurity+jwt實現(xiàn)互踢功能,需要的朋友可以參考下2021-11-11java利用JEXL實現(xiàn)動態(tài)表達式編譯
這篇文章主要介紹了java利用JEXL實現(xiàn)動態(tài)表達式編譯,系統(tǒng)要獲取多個數(shù)據(jù)源的數(shù)據(jù),并進行處理,最后輸出多個字段。字段的計算規(guī)則一般是簡單的取值最多加一點條件判斷,下面是具體的實現(xiàn)方法2021-04-04詳解Java中的do...while循環(huán)語句的使用方法
這篇文章主要介紹了Java中的do...while循環(huán)語句的使用方法,是Java入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下2015-10-10SpringBoot+MyBatis-Plus實現(xiàn)數(shù)據(jù)庫讀寫分離的代碼示例
在當今互聯(lián)網(wǎng)應(yīng)用中,數(shù)據(jù)庫讀寫分離是提高系統(tǒng)性能和穩(wěn)定性的重要手段之一,通過將讀操作和寫操作分別路由到不同的數(shù)據(jù)庫節(jié)點,可以有效減輕數(shù)據(jù)庫服務(wù)器的負擔,本文將介紹如何利用SpringBoot和MyBatis-Plus框架實現(xiàn)數(shù)據(jù)庫讀寫分離,需要的朋友可以參考下2023-11-11手把手教學(xué)Win10同時安裝兩個版本的JDK并隨時切換(JDK8和JDK11)
最近在學(xué)習(xí)JDK11的一些新特性,但是日常使用基本上都是基于JDK8,因此,需要在win環(huán)境下安裝多個版本的JDK,下面這篇文章主要給大家介紹了手把手教學(xué)Win10同時安裝兩個版本的JDK(JDK8和JDK11)并隨時切換的相關(guān)資料,需要的朋友可以參考下2023-03-03