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