1. 程式人生 > >享元模式的簡單使用

享元模式的簡單使用

int 部分 差異 允許 print art HA 鍵值對 但是

前言

享元模式是一種軟件設計模式,是對象池的一種實現,其目的在於盡可能的減少內存的使用量,內存屬於稀缺資源,如果在一個系統中有很多個完全相同或相似的對象,我們就可以使用享元模式,讓他們共享一份內存,不必每個都去實例化對象,從而節省內存,其實現共享的關鍵在於區分內部和外部狀態,內部可共享,外部不可共享,從而實現高效重用。

角色扮演

FlyWeight: 抽象享元類,可以使一個接口也可以是抽象類,聲明方法用於提供內部狀態和設置外部狀態。
DisparateObject:不可共享的狀態類,用於享元對象內差異的部分。
ConcreteFlyWeight:具體享元類,為內部狀態提供成員變量的存儲。
FlyWeightFactory:享元工廠類,創建並管理享元對象,一般管理Map類似的鍵值對象。

適用場景

系統中存在大量的相似對象,或者需要緩沖池的場景,亦或是細粒度的對象都具備相似的外部狀態,而且內部狀態與環境無關的場景;換言之,能夠共享數據對象的場景,應該避免多次new對象,而應該考慮復用對象。

Demo

抽象一個簡單的業務流程:紅牛每瓶飲料都會有一個二維碼,掃描二維碼就知道是否中獎,我們簡化二維碼為中獎文字,都會在瓶蓋上,瓶蓋的形狀和顏色是可以提取為相似的部分的,然後中獎信息每個瓶蓋都不一樣,所以為有差異的非共享成員,那麽簡單的實現一下這個場景。

首先抽象出一個享元接口BottleCap:

package com.demo.flyweight;

/**
 * Created by italkbb on 2018/1/18.
 */

public interface BottleCap {
    // 瓶蓋分為多種顏色
    String getColor();
    // 瓶蓋裏二維碼信息
    String disQRContent(QRContent qrConten);
}

然後定義一個不能共享的QRContent對象,代表每個瓶蓋裏面的二維碼信息。

package com.demo.flyweight;

import java.util.Random;
import java.util.UUID;

/**
 * Created by italkbb on 2018/1/18.
 */

class QRContent {
    // 二維碼信息
    private String mQRContent;
    // 唯一UUID
    private String mUUid;

    public QRContent(){
        mUUid = String.valueOf(UUID.randomUUID());
    }

    public String getmQRContent() {
        mQRContent = "二維碼唯一ID:" + mUUid + "\n" + "根據ID得到中獎信息:" +  (new Random().nextInt(6) + 1)  + "等獎";
        return mQRContent;
    }

    public void setmQRContent(String mQRContent) {
        this.mQRContent = mQRContent;
    }
}

其實這個QR對象就是一般對象,因為其不具備共享的條件,所以就不需要實現享元接口,接下來我們定義可共享的具體享元類ConcreteBottleCap:

package com.demo.flyweight;

/**
 * Created by italkbb on 2018/1/18.
 */

public class ConcreteBottleCap implements BottleCap{
    private String mColor;

    public ConcreteBottleCap(String color){
        super();
        this.mColor = color;
    }
    @Override
    public String getColor() {
        return mColor;
    }

    @Override
    public String disQRContent(QRContent qrContent) {
        return "瓶蓋顏色:" + this.mColor + "\n" + "二維碼內容:" + qrContent.getmQRContent();
    }
}

根據角色扮演部分的組成元素,我們還需要定義享元工廠類BottleFlyWeightFactory:

package com.demo.flyweight;

import java.util.HashMap;
import java.util.Map;

/**
 * Created by italkbb on 2018/1/18.
 */

public class BottleFlyWeightFactory {
    //享元池
    private static Map<String,BottleCap> map=new HashMap<String,BottleCap>();

    public static BottleCap getBottleCap(String color){
        if(map.get(color)!=null){
            return map.get(color);
        }else{
            BottleCap cfw=new ConcreteBottleCap(color);
            map.put(color, cfw);
            return cfw;
        }
    }
}

接下來就是怎麽使用了:

        BottleCap bottleCap1 = BottleFlyWeightFactory.getBottleCap("藍色");
        BottleCap bottleCap2 = BottleFlyWeightFactory.getBottleCap("藍色");

        // 享元成員
        Log.e("zkh1",bottleCap1+"");
        Log.e("zkh2",bottleCap2+"");

        // 這裏是對象有差異的元素
        Log.e("獲獎結果",bottleCap1.disQRContent(new QRContent()));
        Log.e("獲獎結果",bottleCap2.disQRContent(new QRContent()));

我們來看看打印結果:

01-18 18:14:21.348 28974-28974/teltplay.example.com.kotlindemo E/zkh1: com.demo.flyweight.ConcreteBottleCap@dbe1091
01-18 18:14:21.348 28974-28974/teltplay.example.com.kotlindemo E/zkh2: com.demo.flyweight.ConcreteBottleCap@dbe1091
01-18 18:14:21.349 28974-28974/teltplay.example.com.kotlindemo E/獲獎結果: 瓶蓋顏色:藍色
                                                                       二維碼內容:二維碼唯一ID:2767e830-95c4-4c2c-9d81-83278e837d8b
                                                                       根據ID得到中獎信息:3等獎
01-18 18:14:21.349 28974-28974/teltplay.example.com.kotlindemo E/獲獎結果: 瓶蓋顏色:藍色
                                                                       二維碼內容:二維碼唯一ID:821ad12b-dbd4-4c57-a8cf-d90d57e6599d
                                                                       根據ID得到中獎信息:5等獎

結果已經很明顯了吧。

後記

享元模式大幅度的降低了內存的使用數量,但是也犧牲了一些東西,比如邏輯復雜了,我們共享了部分變量又區別對待了不能共享的部分,其次對於外部對象,讀取消耗的時間會比正常訪問長一些,協調利弊才是使用設計模式的檢驗標準。

版權聲明:本文為博主原創文章,未經博主允許不得轉載。 http://blog.csdn.net/u012359453/article/details/79099471

享元模式的簡單使用