Android学习CursorWrapper与Decorator模式 (转至http://www.cnblogs.com/bastard/archive/2012/05/31/2527944.html)
一 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();
}
}
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();
}
}
Android学习CursorWrapper与Decorator模式 (转至http://www.cnblogs.com/bastard/archive/2012/05/31/2527944.html)的更多相关文章
- 爬虫基础学习  转【http://www.cnblogs.com/huangxincheng/archive/2012/11/08/2759752.html】
		这一篇我们聊聊在页面抓取时应该注意到的几个问题. 一:网页更新 我们知道,一般网页中的信息是不断翻新的,这也要求我们定期的去抓这些新信息,但是这个“定期”该怎么理解,也就是多长时间需要 抓一次该页面, ... 
- Hadoop上的中文分词与词频统计实践 (有待学习 http://www.cnblogs.com/jiejue/archive/2012/12/16/2820788.html)
		解决问题的方案 Hadoop上的中文分词与词频统计实践 首先来推荐相关材料:http://xiaoxia.org/2011/12/18/map-reduce-program-of-rmm-word-c ... 
- Android学习链接大放送
		虽然贴链接这种事情..真是一种很偷懒的做法... 但是我一个小菜鸟,果断还是要以多向别人学习为主... 好资源要和大家分享对不对! 况且..放博客里..比收藏夹的利用几率要大一点! 原作者应该也很喜欢 ... 
- Android学习笔记——Activity的启动和创建
		http://www.cnblogs.com/bastard/archive/2012/04/07/2436262.html Android Activity学习笔记——Activity的启动和创建 ... 
- android学习笔记六——Spinner
		注:参考http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0105/2264.html Spinner ==> Spinner ... 
- openfire Android学习(一)----实现用户注册、登录、修改密码和注销等
		以前学习过用Scoket 建立聊天,简单的建立聊天是没问题的,但如果要实现多人复杂的聊天,后台服务器代码就比较复杂,对于我这新手来讲就比较难了.后来在网上看到用openfire做服务器,利用强大的Sm ... 
- Android学习总结——Content Provider
		原文地址:http://www.cnblogs.com/bravestarrhu/archive/2012/05/02/2479461.html Content Provider内容提供者 : and ... 
- Android 学习开发笔记《Android认识》
		1. Android:2007年11月5日第一版,2009年5月豪华版,2010年HTC手机 2. Android框架主要:应用程序.应用程序框架.函数库.运行时. ... 
- Android学习笔记_65_登录功能本身没有任何特别
		对于登录功能本身没有任何特别,使用httpclient向服务器post用户名密码即可.但是为了保持登录的状态(在各个Activity之间切换时要让网站知道用户一直是处于登录的状态)就需要进行cooki ... 
随机推荐
- 使用Spring boot开发RestFul 风格项目PUT/DELETE方法不起作用
			在使用Spring boot 开发restful 风格的项目,put.delete方法不起作用,解决办法. 实体类Student @Data public class Student { privat ... 
- 进程间通信(java)--队列
			前言: 在新增的Concurrent包中,BlockingQueue很好的解决了多线程中,如何高效安全“传输”数据的问题.通过这些高效并且线程安全的队列类,为我们快速搭建高质量的多线程程序带来极大的便 ... 
- window 2008 定时任务调用bat不成功的解决方法
			之前一直有在一台XP的机器上调用定时任务.如今这台机器换成了window 2008的操作系统,调用一直不成功.只是在偶然之间攻克了. 选择"任务计划程序" 任务计划程序库 ... 
- HDU 4968 Improving the GPA(dp)
			HDU 4968 Improving the GPA 题目链接 dp.最大最小分别dp一次,dp[i][j]表示第i个人,还有j分的情况,分数能够减掉60最为状态 代码: #include <c ... 
- openvpn上查看谁在连接服务端
			在服务端/etc/openvpn目录里面有ipp.txt和openvpn-status.log,这两个文件里面记录了,访问服务器的ip网段和地址.但是这两个文件也不是专门干这个用的,也算是一种另类的用 ... 
- PHP遍历目录返回统计目录大小实例
			分享一个 PHP遍历目录并返回统计目录大小的方法.代码: <?php $dirname = "test1"; //mkdir($dirname); //遍历一层目录 func ... 
- Js控制弹窗实现在任意分辨率下居中显示
			弹窗居中比较烦人的是怎么才能在任意分辨率下实现居中显示.1,html部分 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transition ... 
- 【Android】3.13 路径规划功能
			分类:C#.Android.VS2015.百度地图应用: 创建日期:2016-02-04 一.简介 线路规划支持以下功能: 公交信息查询:可对公交详细信息进行查询: 公交换乘查询:根据起.终点,查询策 ... 
- posix多线程--线程私有数据
			1.当多个线程共享一个变量时,将该变量定义为静态或外部变量,使用互斥量确保共享变量的安全访问.如果每个线程都需要一个私有变量值,则该值成为线程的私有数据.程序创建一个键,每个线程独立地设定或得到自己的 ... 
- 在Spark中通过Scala + Mongodb实现连接池
			How to implement connection pool in spark https://github.com/YulinGUO/BigDataTips/blob/master/spark/ ... 
