前言
又來梳理知識(shí)點(diǎn)啦!
在有的時(shí)候我們要多次使用某個(gè)類中的公有實(shí)例方法,我們通常的做法是,先new一個(gè)該類的實(shí)例,然后再調(diào)用該類的這個(gè)方法砰左,調(diào)用完畢后這個(gè)類也就變成垃圾。這種調(diào)用方式如果出現(xiàn)的頻率很高场航,會(huì)在對象生成和內(nèi)存占用上浪費(fèi)很多的資源缠导,一個(gè)對象的創(chuàng)建和銷毀是很占資源的。
于是溉痢,偉大的程序員們想到一個(gè)好辦法僻造,嘗試重用現(xiàn)有的同類對象,如果未找到匹配的對象孩饼,則創(chuàng)建新對象髓削。經(jīng)典的享元模式中,是使用一個(gè)map來存儲(chǔ)對象镀娶,相當(dāng)于是一個(gè)對象工廠立膛,客戶端每次都從享元對象工廠中獲取對象。
定義
使用共享對象可有效的支持大量的細(xì)粒度對象
使用場景
- 系統(tǒng)中存在大量的相似對象
- 對象沒有特定的身份梯码,狀態(tài)都較接近
- 需要緩沖池的場景
使用方法
享元模式是一種思想宝泵,一種避免多次重復(fù)創(chuàng)建對象的編程思想。
我們主要是要?jiǎng)?chuàng)建一個(gè)享元工廠忍些,來生產(chǎn)我們的享元類鲁猩。這樣的享元工廠有N種寫法坎怪,我們常見的是使用map來構(gòu)造享元工廠罢坝,來看一個(gè)享元工廠的demo
import java.util.HashMap;
public class ShapeFactory {
private static final HashMap<String, Shape> circleMap = new HashMap();
//使用傳統(tǒng)的map來管理對象
public static Shape getObj(String color) {
Circle circle = (Circle)circleMap.get(color);
if(circle == null) {
circle = new Circle(color);
circleMap.put(color, circle);
System.out.println("Creating circle of color : " + color);
}
return circle;
}
}
Android中的享元模式應(yīng)用
應(yīng)用的話,若我說,我們編寫的ViewHolder都可以歸類為享元工廠的存儲(chǔ)器嘁酿。幾乎到處是應(yīng)用隙券,不過最明顯的是Handler中Message的應(yīng)用。
例如我們發(fā)送個(gè)0給handler自己闹司。
handler.obtainMessage(0).sendToTarget();
我們進(jìn)去看Handler的源碼娱仔,obtainMessage如下
public final Message obtainMessage(int what, int arg1, int arg2, Object obj)
{
return Message.obtain(this, what, arg1, arg2, obj);
}
我們發(fā)現(xiàn),其中調(diào)用了Message.obtain游桩,我們再去看Message的實(shí)現(xiàn)
public static Message obtain(Handler h, int what,
int arg1, int arg2, Object obj) {
Message m = obtain();
m.target = h;
m.what = what;
m.arg1 = arg1;
m.arg2 = arg2;
m.obj = obj;
return m;
}
//獲取一個(gè)空message
public static Message obtain() {
synchronized (sPoolSync) {
//從對象Message中獲取message
if (sPool != null) { //private static Message sPool;
Message m = sPool;
sPool = m.next;
//清空message屬性
m.next = null;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
}
}
return new Message();
}
我們可以看到牲迫,sPool指向的是一個(gè)鏈表,其實(shí)這個(gè)鏈表是存儲(chǔ)我們用過的Message的借卧,當(dāng)我們obtain一個(gè)Message的時(shí)候盹憎,會(huì)去取鏈表中的第一個(gè),并把sPool指向下一個(gè)铐刘,同時(shí)把取到的置空陪每。
/*Message的回收方法*/
public void recycle() {
if (isInUse()) {
if (gCheckRecycle) {
throw new IllegalStateException("This message cannot be recycled because it "
+ "is still in use.");
}
return;
}
recycleUnchecked();
}
void recycleUnchecked() {
// Mark the message as in use while it remains in the recycled object pool.
// Clear out all other details.
flags = FLAG_IN_USE;
what = 0;
arg1 = 0;
arg2 = 0;
obj = null;
replyTo = null;
sendingUid = -1;
when = 0;
target = null;
callback = null;
data = null;
/*將用過的Message放入鏈表中*/
synchronized (sPoolSync) {
if (sPoolSize < MAX_POOL_SIZE) {
next = sPool;
sPool = this;
sPoolSize++;
}
}
}
我們可以知道Message的享元模式不是使用的傳統(tǒng)的map方式,而是自己構(gòu)建一個(gè)鏈表镰吵,靈活使用我們的享元模式思想才是重點(diǎn)檩禾。
謝謝大家閱讀,如有幫助疤祭,來個(gè)喜歡或者關(guān)注吧盼产!
本文作者:Anderson/Jerey_Jobs
博客地址 : 夏敏的博客/Anderson大碼渣/Jerey_Jobs
簡書地址 : Anderson大碼渣
CSDN地址 : Jerey_Jobs的專欄
github地址 : Jerey_Jobs