設計模式21—設計模式之享元模式(Flyweight)(結構型)

來源:互聯網
上載者:User
1.講解享元模式(結構型)1.1享元模式定義

運用共用技術有效地支援大量細粒度對象.
享元:把內部狀態共用出來
1.2享元模式要點

重點在於分離變與不變。
把一個對象的狀態分為內部狀態和外部狀態,內部狀態不變,外部狀態可變。
內部狀態就是在對象裡通過內部方法管理,而外部資訊可以在通過外部刪除或者儲存。
1.3享元模式的結構圖以及說明

 
享元模式所涉及的角色有抽象享元角色、具體(單純)享元角色、複合享元角色、享員工廠角色,以及用戶端角色等。

抽象享元角色(Flyweight):此角色是所有的具體享元類的超類,為這些類規定出需要實現的公用介面或抽象類別。那些需要外蘊狀態(External State)的操作可以通過方法的參數傳入。抽象享元的介面使得享元變得可能,但是並不強制子類實行共用,因此並非所有的享元對象都是可以共用的。

具體享元(ConcreteFlyweight)角色:實現抽象享元角色所規定的介面。如果有內蘊狀態的話,必須負責為內蘊狀態提供儲存空間。享元對象的內蘊狀態必須與對象所處的周圍環境無關,從而使得享元對象可以在系統內共用。有時候具體享元角色又叫做單純具體享元角色,因為複合享元角色是由單純具體享元角色通過複合而成的。

複合享元(UnsharableFlyweight)角色:複合享元角色所代表的對象是不可以共用的,但是一個複合享元對象可以分解成為多個本身是單純享元對象的組合。複合享元角色又稱做不可共用的享元對象。這個角色一般很少使用。

享元工廠(FlyweightFactoiy)角色:本角色負責建立和管理享元角色。本角色必須保證享元對象可以被系統適當地共用。當一個用戶端對象請求一個享元對象的時候,享元工廠角色需要檢查系統中是否已經有一個符合要求的享元對象,如果已經有了,享元工廠角色就應當提供這個已有的享元對象;如果系統中沒有一個適當的享元對象的話,享元工廠角色就應當建立一個新的合適的享元對象。

用戶端(Client)角色:本角色還需要自行儲存所有享元對象的外蘊狀態。
1.4享元模式的範例程式碼

package demo19.flyweight.example2;/*** * 享元介面,通過這個介面享元可以接受並作用於外部狀態 */public interface Flyweight {/** * 樣本操作,傳入外部狀態 *  * @param extrinsicState *        樣本參數,外部狀態 */public void operation(String extrinsicState);}**************************************************************************************************package demo19.flyweight.example2;/** * 享元對象 */public class ConcreteFlyweight implements Flyweight {/** * 樣本,描述內部狀態 */private String intrinsicState;/** * 構造方法,傳入享元對象的內部狀態的資料 *  * @param state *        享元對象的內部狀態的資料 */public ConcreteFlyweight(String state) {this.intrinsicState = state;}public void operation(String extrinsicState) {// 具體的功能處理,可能會用到享元內部、外部的狀態}}**************************************************************************************************package demo19.flyweight.example2;/** * 不需要共用的Flyweight對象, 通常是將被共用的享元對象作為子節點,組合出來的對象 */public class UnsharedConcreteFlyweight implements Flyweight {/** * 樣本,描述對象的狀態 */private String allState;public void operation(String extrinsicState) {// 具體的功能處理}}**************************************************************************************************package demo19.flyweight.example2;import java.util.HashMap;import java.util.Map;/** * 享元工廠 */public class FlyweightFactory {/** * 緩衝多個flyweight對象,這裡只是示意一下 */private Map<String, Flyweight> fsMap = new HashMap<String, Flyweight>();/** * 擷取key對應的享元對象 *  * @param key *        擷取享元對象的key,只是示意 * @return key對應的享元對象 */public Flyweight getFlyweight(String key) {// 這個方法裡面基本的實現步驟如下:// 1:先從緩衝裡面尋找,是否存在key對應的Flyweight對象Flyweight f = fsMap.get(key);// 2:如果存在,就返回相對應的Flyweight對象if (f == null) {// 3:如果不存在// 3.1:建立一個新的Flyweight對象f = new ConcreteFlyweight(key);// 3.2:把這個新的Flyweight對象添加到緩衝裡面fsMap.put(key, f);// 3.3:然後返回這個新的Flyweight對象}return f;}}**************************************************************************************************package demo19.flyweight.example2;/** * Client對象,通常會維持一個對flyweight的引用, 計算或儲存一個或多個flyweight的外部狀態 */public class Client {// 具體的功能處理}
1.5享元模式的本質

分離與共用
1.6享元模式的優缺點

優點:減少對象數量,節省記憶體空間
缺點:維護共用對象,需要額外開銷
1.7何時選用?

1.7.1如果一個程式大量使用了細粒度對象
1.7.2如果對象的大多數狀態都可以變為外部狀態(比如可以通過計算得到),或是從外部傳入等,可以使用享元模式進行內部狀態和外部狀態的分離。
2.使用享元模式解決的案例

比如圍棋有300顆棋子,用一般的設計模式,建立一個類,每個棋子都用一個對象的話,那就會非常麻煩,並且各自訂各自在棋盤的位置.....等等,而使用 亨元模式 來實現的話,就用兩個對象 :一個黑,一個白。這樣就可以了,至於棋子的方位不同,那隻是對象的不同的外部表格現形式或者說是外部狀態。這樣三百多個對象就減到了兩個對象。享元模式以共用的方式高效地支援大量的細粒度對象,說的再具體一些是將所有具有相同狀態的對象指向同一個引用,從而解決了系統在建立大量對象時所帶來的記憶體壓力。
範例程式碼如下
2.1享元介面,通過這個介面享元可以接受並作用於外部狀態

package demo19.flyweight.example1;/** * 抽象棋子的介面 *  * @author 王玉超 * @date 2013-7-31 */public interface IChessFlyWeight {public String getColor();public void show(Point point);}
2.2享元對象
package demo19.flyweight.example1;/** * 具體棋子物件的實作類別 *  * @author 王玉超 * @date 2013-7-31 */public class ConcreteChessFlyWeight implements IChessFlyWeight {private String color;public String getColor() {return color;}public ConcreteChessFlyWeight(String color) {this.color = color;}public void show(Point point) {System.out.println("This Chess is " + color + ",Point X:" + point.getX() + "  Y:" + point.getY());}}
2.3不需要共用的對象,即外部動態該變數
package demo19.flyweight.example1;/** * 棋子外部動態變動的屬性 *  * @author 王玉超 * @date 2013-7-31 */public class Point {private int x;private int y;public Point(int x, int y) {this.x = x;this.y = y;}public int getX() {return x;}public int getY() {return y;}@Overridepublic String toString() {return "Point [x=" + x + ", y=" + y + "]";}}
2.4享元模型對象工廠
package demo19.flyweight.example1;import java.util.HashMap;import java.util.Map;/** * 享元模型對象工廠 *  * @author 王玉超 * @date 2013-7-31 */public class ChessFlyWeightFactory {private Map<String, IChessFlyWeight> chessMap = new HashMap<String, IChessFlyWeight>();public IChessFlyWeight getChess(String key) {if (!chessMap.containsKey(key)) {chessMap.put(key, new ConcreteChessFlyWeight(key));}return chessMap.get(key);}}
2.5用戶端調用
package demo19.flyweight.example1;public class Client {public static void main(String[] args) {ChessFlyWeightFactory factory = new ChessFlyWeightFactory();Point point;String white = "白";String black = "黑";point = new Point(0, 0);factory.getChess(white).show(point);point = new Point(10, 10);factory.getChess(white).show(point);point = new Point(100, 100);factory.getChess(black).show(point);point = new Point(200, 200);factory.getChess(black).show(point);}}

代碼仔細對應範例程式碼以後,發現沒有【不需要共用的Flyweight對象】實際上,就是Point類,只不過,Point類沒有繼承Flyweight介面而已。那個不需要共用的對象一般很少用。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.