一 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)的更多相关文章

  1. 爬虫基础学习 转【http://www.cnblogs.com/huangxincheng/archive/2012/11/08/2759752.html】

    这一篇我们聊聊在页面抓取时应该注意到的几个问题. 一:网页更新 我们知道,一般网页中的信息是不断翻新的,这也要求我们定期的去抓这些新信息,但是这个“定期”该怎么理解,也就是多长时间需要 抓一次该页面, ...

  2. 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 ...

  3. Android学习链接大放送

    虽然贴链接这种事情..真是一种很偷懒的做法... 但是我一个小菜鸟,果断还是要以多向别人学习为主... 好资源要和大家分享对不对! 况且..放博客里..比收藏夹的利用几率要大一点! 原作者应该也很喜欢 ...

  4. Android学习笔记——Activity的启动和创建

    http://www.cnblogs.com/bastard/archive/2012/04/07/2436262.html Android Activity学习笔记——Activity的启动和创建 ...

  5. android学习笔记六——Spinner

    注:参考http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0105/2264.html Spinner ==> Spinner ...

  6. openfire Android学习(一)----实现用户注册、登录、修改密码和注销等

    以前学习过用Scoket 建立聊天,简单的建立聊天是没问题的,但如果要实现多人复杂的聊天,后台服务器代码就比较复杂,对于我这新手来讲就比较难了.后来在网上看到用openfire做服务器,利用强大的Sm ...

  7. Android学习总结——Content Provider

    原文地址:http://www.cnblogs.com/bravestarrhu/archive/2012/05/02/2479461.html Content Provider内容提供者 : and ...

  8. Android 学习开发笔记《Android认识》

    1.          Android:2007年11月5日第一版,2009年5月豪华版,2010年HTC手机 2.          Android框架主要:应用程序.应用程序框架.函数库.运行时. ...

  9. Android学习笔记_65_登录功能本身没有任何特别

    对于登录功能本身没有任何特别,使用httpclient向服务器post用户名密码即可.但是为了保持登录的状态(在各个Activity之间切换时要让网站知道用户一直是处于登录的状态)就需要进行cooki ...

随机推荐

  1. Latex 环境下“中文字体”的使用

    Latex 环境下“中文字体”的使用 使用CTex自带编辑器WinEdt,在该环境下如何使用中文字体呢?作为一个菜鸟,折腾了好几天,最终基本解决了这个问题.现在整理下,分享给后来者. 对于使用中文字体 ...

  2. 多主机共享ssh Public/Private Key

    前期服务器比较少,所有代码都放在github的私库中,在自己的github 设置中设置SSH keys就可以拉下相应的库中的代码到本地与服务器了,但是最近服务器多家了几台,每台都生成key加到gith ...

  3. laravel5的Bcrypt加密方式对系统保存密码

    laravel5文档介绍 //对 A 密码使用Bcrypt 加密 $password = Hash::make('mima'); //你也可直接使用 bcrypt 的 function $passwo ...

  4. Mac中提升权限修改系统目录

    原来OSX EI Capitan中增加了一个SIP功能,不管你是不是su,都会阻止你在系统目录下进行操作.如果,想要修改系统目录的文件,如升级bash,需要修改/bin/bash,那么就要先关闭SIP ...

  5. js实现拉伸拖动iframe的具体代码

    这篇文章介绍了js实现拉伸拖动iframe的具体代码,有需要的朋友可以参考一下左边iframe放树目录,右边的iframe放index页.拖鼠标同时控制2个iframe的宽高.期待有人能改进.操作方法 ...

  6. 【Android】3.3 MapFragment的使用

    分类:C#.Android.VS2015.百度地图应用: 创建日期:2016-02-04 3.3 示例3--MapFragment的使用 一.简介 TextureMapFragment:用于显示地图片 ...

  7. 每日英语:Cyclists Live Six Years Longer

    Cycling does the body good. New data from Tour de France cyclists finds that those athletes live an ...

  8. 这个BUG你遇到过吗

    今天做项目的时候,当我根据文档集成极光推送的时候,需要导入一些framework 然后我用真机iPhone5c调试的时候,出错 程序停止到这里了,而且,点击下一步,程序并没有什么反应,各位大神有知道原 ...

  9. CSocket类网络编程 MFC

    Visual C++的MFC提供了CSocket类用来实现网络通信. 下面介绍VC++在Windows 95中实现Socket的 CSocket 类相关成员函数(这些成员函数实际上是从CAsyncSo ...

  10. java timer timertask mark

    其实就Timer来讲就是一个调度器,而TimerTask呢只是一个实现了run方法的一个类,而具体的TimerTask需要由你自己来实现,例如这样: 1 2 3 4 5 6 Timer timer = ...