Android学习CursorWrapper与Decorator模式

Android学习CursorWrapper与Decorator模式 - Dufresne - 博客园

一 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();
    }
}

时间: 2024-10-13 01:24:49

Android学习CursorWrapper与Decorator模式的相关文章

Android学习CursorWrapper与Decorator模式 (转至http://www.cnblogs.com/bastard/archive/2012/05/31/2527944.html)

一 Decorator模式 意图: 动态的给一个对象添加一些额外的职责.就增加功能来说,Decorator模式相比生成子类更为灵活. 动态的给一个对象,而不是对整个类添加额外职责,说明此模式将采用的结构是组合而不是继承: 要给一个对象添加职责,通常可以使用其类的派生类对象替换当前对象,但这显得不够灵活, 继承结构属于静态形式,系统往往并不知道有这样的类存在: 而我们需要的在某些时刻让对象具有一些额外的职责,额外的职责很可能是来自我们自己的扩展或者某些时刻的特定需求等. 于是通过一种方式对现有的对

Android学习——ActivityManager与Proxy模式的运用

Android学习--ActivityManager与Proxy模式的运用 - Dufresne - 博客园 一 Proxy模式 意图: ?????? 为其他对象提供一种代理以控制这个对象的访问. 适用性: l? 远程代理( Remote Proxy ): 为一个对象在不同的地址空间提供局部代表. l? 虚代理(Virtual Proxy)根据需要创建开销很大的对象.使用一个代理对象作为代表,在真正的需要时进行创建. l? 保护代理(Protection Proxy):控制对原始对象的访问.保护

Android学习之访问者模式详解

本文和大家分享的主要是android设计模式中的访问者模式相关内容,一起来看看吧,希望对大家学习android有所帮助. 访问者模式 访问者模式属于行为模式. 访问者模式中属于相对比较复杂的一类,它会在A中让B访问,而实际在B中实际调用的是A的方法. class A { public void method1(){ System.out.println("AAAAAA"); } public void method2(B b){ b.showA(this); } } class B {

【转】 Pro Android学习笔记(五二):ActionBar(5):list模式

可以在action bar中加入spinner的下来菜单,有关spinner,可以参考Pro Android学习笔记(二十):用户界面和控制(8):GridView和Spinner. list的样式和theme有关,如果theme设置不正确,还可能会出现异常. 相关的代码如下: public class ListActionBarDemo extends SearchTestCase3 implements OnNavigationListener{ //List触发的回调函数接口    @Ov

【转】 Pro Android学习笔记(五一):ActionBar(4):标准和Tab模式

之前,我们学习的Action Bar是标准模式,Tab模式的如下图所示. 对于Tab,我们在Android学习笔记(二二): 多页显示-Tag的使用中学习过,但Action Bar的tab更适合fragment的使用.我们在之前实现的标准Action Bar的基础上添加导航用的tab,代码如下: public class TabbedActionBarDemo extends SearchTestCase3 implements ActionBar.TabListener{    @Overri

Android学习按键事件监听与Command模式

Android学习按键事件监听与Command模式 - Dufresne - 博客园 ? 一 Command模式 意图: 将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化: 对请求排队或记录请求日志,以及支持可撤销的操作. 将请求被封装成一个对象,当向某对象提交请求时,使我们可以不用去知道被具体的请求的操作或者请求的接收者, 实现了动作的请求者对象和动作的执行者对象之间的解耦合. 适用性: 使用Command模式代替callback形式的回调应用: 在不同的时刻指定.排列和执行请

【转】 Pro Android学习笔记(十九):用户界面和控制(7):ListView

目录(?)[-] 点击List的item触发 添加其他控件以及获取item数据 ListView控件以垂直布局方式显示子view.系统的android.app.ListActivity已经实现了一个只含有一个ListView的Activity,并通过setListAdapter()方法来管理adapter.我们可以通过扩展ListActivity来实现. 我们要在整个屏幕上显示ListView,我们直接继承使用ListActivity,不需要在定义自己的layout XML文件,我们在上一学习中

设计模式学习03—抽象工厂模式

1.动机与定义 工厂模式中,一个工厂仅仅能提供一个或一类产品,当产品种类较多,形成产品系列(比方我们要创建跨平台的button,菜单,文本框等等一系列GUI控件: 单纯使用工厂模式会产生大量工厂,并且后期维护也不方便,我们能够从产品中找到规律,假设产品等级相对固定,以后仅仅会新增产品族,那么我们就能够把整个产品族放到一个工厂创建,以后新增其它系统产品族也很方便,例如以下图: 这样的模式就是抽象工厂,工厂方法模式针对的是一个产品等级结构,而抽象工厂模式则须要面对多个产品等级结构,一个工厂等级结构能

Android学习笔记(十四)——在运行时添加碎片(附源码)

在运行时添加碎片 点击获取源码 将UI分割为多个可配置的部分是碎片的优势之一,但其真正强大之处在于可在运行时动态地把它们添加到活动中. 1.使用上一篇创建的Fragments项目,在main.xml文件中注释掉两个<fragment>元素: 2.在FragmentActivity.java中添加下面的代码: FragmentManager fragmentManager = getSupportFragmentManager();//向活动添加碎片 FragmentTransaction fr