Android學習CursorWrapper與Decorator模式
一 Decorator模式
意圖:
動態的給一個對象添加一些額外的職責。就增加功能來說,Decorator模式相比生成子類更為靈活。
動態的給一個對象,而不是對整個類添加額外職責,說明此模式將采用的結構是組合而不是繼承;
要給一個對象添加職責,通常可以使用其類的派生類對象替換當前對象,但這顯得不夠靈活,
繼承結構屬於靜態形式,系統往往並不知道有這樣的類存在;
而我們需要的在某些時刻讓對象具有一些額外的職責,額外的職責很可能是來自我們自己的擴展或者某些時刻的特定需求等。
於是通過一種方式對現有的對象進行動態的包裝(Wrapper)和進行修飾(Decorator),
所以如果能夠動態的給對象添加某些職責功能將使系統變得更加靈活和具有擴展性。
適用性:
l 在不影響其他對象的情況下,以動態、透明的方式給單個對象添加職責;
l 處理那些可以撤銷的職責;
l 當不適合采用生成子類的方法進行擴充時:一種情況是支持每一種組合將產生大量子類,
另一種情況是類定義被隱藏無法得知具體的類;
結構:
理解:
在初次學習Decorator模式的時候,我產生如下疑問:
我覺得使用Deccorator或許並不好用,Decorator讓對象被裝飾進行包裝,得到的將是一個被裝飾后的對象,而已不是對象本身。
雖然可以通過Decorator傳遞請求,但勢必讓事情變得更麻煩。故通常我們仍然需要操作的是原對象本身。
這樣一來需要維護兩個對象……麻煩,Why?
結果的確是這樣:需要通過Decorator傳遞對原對象的請求,讓結構層次變得較深稍微復雜,
如果使用繼承(假設讓某Commponent繼承某Decorator),構造一個更復雜的類,我們就可以直接維護一個對象即可。
但是使用繼承我們實際上需要維護的職責功能沒有變,仍然是兩個部分:Decorator和Component;
在大多數情況下我們可能根本不需要Decorator而只需要Commponent部分,沒能做到在需要時動態添加功能;
使用Decorator去動態的包裝Component,可以做到“即付即用”的方法添加職責,
也可以逐步的個一個簡單對象添加職責構造復雜的對象;對象的維護具有層次性:客戶端僅僅需要維護Decorator即可,
被裝飾的對象交給Decorator來維護即可,還降低了復雜性。
能做到如此最重要的是:Decorator是一個透明的包裝;也就說被包裝后的對象和被包裝的對象具有一致性,
在使用裝飾對象時就像使用原對象一樣,而不需要加以區分;故要使Decorator和Component具有一致的接口,
從同一個父類派生下來——保持接口的一致性。
Decorator是對象的裝飾包裝,Decorator如果太復雜,有可能破壞Decorator與Component的一致性,
故Decorator盡量保持簡單所添加的職責單一。
所以Decorator要做到:動態的包裝對象,添加對象新的職責,保持與原對象一致性;
二 Android中Cursor應用
Cursor:數據庫查詢的時候返回的數據集合類型,提供用來訪問其中元素的接口;public interface Cursor {};
其中提供了很多方法來訪問數據庫中存儲的元素:光標移動和數據獲取等;提供了對於數據查詢結果處理通用的接口;
CursorWrapper:public class CursorWrapper implements Cursor 是對Cursor的一個包裝,
可以看到實現的接口中都是直接對Cursor接口的包裝而沒有干其他事情,這樣看來好像沒有什么意義;
是直接使用Cursor還是使用CursorWrapper沒有任何區別;但是CursorWrapper也沒有提供任何額外的職責和功能。
CursorWrapper作用:包裝一個Cursor類,代理對一個Cursor對象所有的方法調用;主要的用途就是重寫Cursor中某些方法進行擴展。
所以僅僅是提供這樣一個類,使我們可以重寫其中某些方法進行擴展的,直接從Cursor繼承需要重寫所有接口太多沒有意義。
代碼中對此使用所見並不多,下面用一個簡單的信息排序的例子來學習這種模式。
三 信息對話排序
有這樣一個需求:
信息中對話主界面的列表顯示是根據時間先后來排序的;對於信息量非常大的用戶來說,
有些未讀信息可能排在后面查找不是很方便,或者最重要的是:未讀信息應排在前,而不應該是按照時間排序。
信息是以數據庫的方式進行存儲的,進入信息時,查詢返回的結果就是一個Curosr類型的對象,然后去更新顯示列表;
要對此進行排序首先Cursor本身是不具備此功能的,並且Cursor也是只能讀不能寫的;
要對信息列表排序,數據在Cursor里面不能改變,怎么排序呢?對顯示后的ViewItem進行排序,
但是ViewItem是按需創建的也不行;只能對Cursor進行改造了。
Cursor沒有排序的功能那我們就給Cursor增加一個排序共功能的包裝;並保證包裝后的接口一致;
使其在使用中仍然顯示用原來的Cursor一樣。
因此按照信息模塊的實現框架,調整后其結構如下:
——>ConversationList得到查詢后的數據類型Cursor,
——>創建CursorThreadMsgSort對象將其包裝起來,
——>再傳遞給ConversationListAdapter(維護Cursor數據提取)。
——>此時的Cursor就是裝飾后的對象,添加了排序的職責。
為什么不使用繼承的方式呢?這里可以看到我們從數據庫查詢得到的是一個Cursor(接口),
而根本不知道具體的類是哪一個;即使知道了也是無法替換的,因為系統提供的是一個通用的數據查詢方式,
而排序功能是一個特殊的應用,無法更改;所以只能在使用時動態的進行替換以添加排序的職責。
下面就是排序的具體實現。
四 對Cursor排序實現
對Cursor排序不管怎樣實現,Cursor是不能夠改變的;能改變的是重寫其中的方法,光標移動位置等;
而排序本身就是數據比較位置的移動,Cursor位置不能移動,但是只要得到合適的位置數據,就可以實現排序。
所以我們只要對Cursor建立一張對應的長度和Cursor一致的索引表,表按照規則是經過排序,表中每一項對應的是Cursor中的位置。
在移動光標的時候實際上按照表的對應位置移動即可。
下面看看具體的實現就比較簡單了。
可參考:http://blog.csdn.net/yangzongquan/article/details/6547860 對Cursor排序方法。
信息排序實現代碼:

package com.android.mms.ui; import android.database.CursorWrapper; import android.database.Cursor; import java.util.ArrayList; import java.util.List; import android.util.Log; import java.util.Collections; import java.util.Comparator; public class ThreadMsgSortCursor extends CursorWrapper { private static final String LOGTAG = "xmp_sort_1"; public static final int SORT_BY_TIME = 1; public static final int SORT_BY_READ = 2; public static final int SORT_BY_NAME = 3; private static final int ID = 0; private static final int DATE = 1; private static final int RECIPIENT_IDS = 3; private static final int READ = 6; private int mSortType ; private int mPos; private List<SortEntry> mSortList; /** * * @param cursor * @param sortType */ public ThreadMsgSortCursor(Cursor cursor,int sortType) { super(cursor); mSortType = sortType; mPos = -1; initSortList(); EexecuteSortList(); } /** * 建立與Cursor對應的索引表 */ protected void initSortList(){ int i = 0; if(mSortList != null){ mSortList.clear(); } else{ mSortList = new ArrayList<SortEntry>(); } while(mCursor.moveToNext()){ SortEntry sortKey = new SortEntry(); sortKey.mNameIds = mCursor.getString(RECIPIENT_IDS); sortKey.mRead = mCursor.getInt(READ); sortKey.mDate = mCursor.getLong(DATE); sortKey.mOrder = i++; Log.v(LOGTAG,sortKey.toString()); mSortList.add(sortKey); } } /** * 對表進行排序 */ protected void EexecuteSortList(){ if(mSortList == null){ return; } ComparatorEx comparator = new ComparatorEx(); Collections.sort(mSortList,comparator); for (int i = 0; i < mSortList.size(); i++) { Log.v(LOGTAG,mSortList.get(i).toString()); } } /** * 索引表數據 */ public class SortEntry{ public String mNameIds; public long mDate; public int mRead; //保存閱讀狀態 public int mOrder; public String toString(){ String strInfo = " mOrder" + mOrder + "---->" + " mNameIds--> " + mNameIds + " " + "mDate-->" + mDate + " " + "mRead-->" + mRead + " "; return strInfo; } } /** * 比較 */ public class ComparatorEx implements Comparator{ @Override public int compare(Object obj1, Object obj2) { SortEntry entry1 = (SortEntry)obj1; SortEntry entry2 = (SortEntry)obj2; switch (mSortType) { case SORT_BY_TIME: return compareByTime(entry1,entry2); case SORT_BY_READ: return compareByRead(entry1,entry2); case SORT_BY_NAME: return compareByName(entry1,entry2); default: return 0; } } /** * 鎸夐槄璇葷姸鎬佹瘮杈冩帓搴? * @param entry1 * @param entry2 * @return */ protected int compareByRead(SortEntry entry1, SortEntry entry2){ Log.v(LOGTAG,"ComparatorEx------->compareByRead"); if (entry1.mRead >= entry2.mRead){ return 1; } else{ return -1; } } protected int compareByName(SortEntry entry1, SortEntry entry2){ return 1; } protected int compareByTime(SortEntry entry1, SortEntry entry2){ return 1; } } /** * 鏍規嵁cursor鐨凱os鑾峰彇涓€涓浉瀵圭殑緔㈠紩琛ㄤ腑瀛樺偍鐨勪綅緗? * @param position * @return */ protected int getRelativePos(int position){ int relativePos = position; switch (mSortType) { case SORT_BY_TIME: break; case SORT_BY_READ: relativePos = mSortList.get(position).mOrder; break; case SORT_BY_NAME: break; default: break; } //閫氳繃log鏌ョ湅瀵瑰簲鍏崇郴 Log.v(LOGTAG,"ThreadMsgSortCursor-->position-->" + position + " relativePos --->" + relativePos); return relativePos; } /** * 浣嶇疆鍙樻崲 鍙栧叾鍦ㄧ儲寮曡〃涓搴斾綅緗? * @param position * @return */ public boolean moveToPosition(int position){ mPos = position; //鑾峰彇鍚堥€傜殑pos int order = getRelativePos(position); return mCursor.moveToPosition(order); } public boolean moveToFirst(){ Log.v(LOGTAG,"ThreadMsgSortCursor---------->moveToFirst------"); return moveToPosition(0); } public boolean moveToLast(){ Log.v(LOGTAG,"ThreadMsgSortCursor---------->moveToLast------"); return moveToPosition(getCount() - 1); } public boolean moveToNext(){ Log.v(LOGTAG,"ThreadMsgSortCursor---------->moveToNext------"); return moveToPosition(mPos + 1); } public boolean moveToPrevious(){ Log.v(LOGTAG,"ThreadMsgSortCursor---------->moveToPrevious------"); return moveToPosition(mPos - 1); } public boolean move(int offset) { Log.v(LOGTAG,"ThreadMsgSortCursor---------->move------"); return moveToPosition(mPos + offset); } public int getPosition() { return mPos; } @Override public void close() { Log.v(LOGTAG,"ThreadMsgSortCursor---------->close------"); mCursor.close(); } }