Android中的设计模式

本文地址:http://blog.csdn.net/mba16c35/article/details/43339401

1.Strategy设计模式

(1)定义:把一系列的算法封装成对象,并使他们可相互替换。这样可以使得算法和使用他们的客户解耦。

(2)例子:

public class MyActivty extends Activity {
  /** Called when the activity is first created. */
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    final TextView myTextView = (TextView)findViewById(R.id.text_view);
    
     // Define the base URI.
     String baseUri = "content://com.paad.earthquake/earthquakes/";
    
     // Contruct an Intent to test if there is an Activity capable of 
     // viewing the content you are Linkifying. Use the Package Manager
     // to perform the test.
     PackageManager pm = getPackageManager();
     Intent testIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(baseUri));
     boolean activityExists = testIntent.resolveActivity(pm) != null;
     
     // Uncomment to apply the match and transform filters
     if (activityExists) {
       int flags = Pattern.CASE_INSENSITIVE;
       Pattern p = Pattern.compile("\\bquake[\\s]?[0-9]+\\b", flags);
       Linkify.addLinks(myTextView, p, baseUri,
           new MyMatchFilter(), new MyTransformFilter());
     }
  }
  
  class MyMatchFilter implements MatchFilter {
    public boolean acceptMatch(CharSequence s, int start, int end) {
      return (start == 0 || s.charAt(start-1) != '!');
    }
  }
class MyTransformFilter implements TransformFilter {
    public String transformUrl(Matcher match, String url) {
      return url.toLowerCase().replace(" ", "");
    }
  }
}

这里的MyMatchFilter和MyTransformFilter就是策略,它们封装了匹配算法并传给Linkify对象。这样只要实现MatchFilter和TransformFilter就可以自定义自己特定算法,而且可以在运行时改变自己自己的算法,因为用的是对象组合的结构。客户则需要针对接口编程,而不受新算法的影响,这里符合了开闭原则(客户对修改封闭,不需要修改客户代码,同时对新算法开放)


2.Adapter模式和观察者模式

(1)定义:

Apdater模式:将一个类的接口转换成客户希望的另外一个接口。Adapter使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。

Observer模式:定义对象间的一对多的依赖关系,当一个对象的状态发生变化时,所有依赖于它的对象都得到通知并被自动更新。

(2)这两个模式在Apater里得到充分运用。

Adapter相当于数据和ListView之间的桥梁,可以适配各种数据类型和扩展了AdapterView的视图组(如ListView或Gallery),堪称Adapter模式的经典例子。Android中的Adapter实际上可以将任意类型的数据和ApaterView之间适配。


另外,当调用Adapter的notifyDataSetChange的时候,实际是运用了观察者模式.

例子:

这是Apdater接口里的两个函数。

/**
     * Register an observer that is called when changes happen to the data used by this adapter.
     *
     * @param observer the object that gets notified when the data set changes.
     */
    void registerDataSetObserver(DataSetObserver observer);

    /**
     * Unregister an observer that has previously been registered with this
     * adapter via {@link #registerDataSetObserver}.
     *
     * @param observer the object to unregister.
     */
    void unregisterDataSetObserver(DataSetObserver observer);</span>

我们看看BaseApdater的实现(和主题无关的我就不复制了)

private final DataSetObservable mDataSetObservable = new DataSetObservable();
    
public void registerDataSetObserver(DataSetObserver observer) {
     mDataSetObservable.registerObserver(observer);
}

public void unregisterDataSetObserver(DataSetObserver observer) {
     mDataSetObservable.unregisterObserver(observer);
}
/**
 * Notifies the attached observers that the underlying data has been changed
 * and any View reflecting the data set should refresh itself.
 */
 public void notifyDataSetChanged() {
     mDataSetObservable.notifyChanged();
 }

代码中的mDataSetObservable意思是可被观察者,指的是BaseApdater自己,这里用了组合而不是继承。当我们调用notifyDataSetChanged的时候,就会调用mDataSetObservalbe的notifyChanged,其中会逐一调用观察者的onChanged函数,那么观察者就知道BaseAdapter的数据有变化并可以做出响应了。

以下是DataSetObservable的notifyChanged函数:

/**
     * Invokes onChanged on each observer. Called when the data set being observed has
     * changed, and which when read contains the new state of the data.
     */
    public void notifyChanged() {
        synchronized(mObservers) {
            // since onChanged() is implemented by the app, it could do anything, including
            // removing itself from {@link mObservers} - and that could cause problems if
            // an iterator is used on the ArrayList {@link mObservers}.
            // to avoid such problems, just march thru the list in the reverse order.
            for (int i = mObservers.size() - 1; i >= 0; i--) {
                mObservers.get(i).onChanged();
            }
        }
    }


还有一个观察者模式的例子是AppWidgetManager中包含的notifyAppWidgetViewDataChanged方法,该方法允许指定一个要更新的WidgetID(或ID数组),以及该Widget中低层数据源已经发生变化的集合View的资源ID:

appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetIds, R.id.widget_stack_view);

这将导致相关的RemoteViewsFactory的onDataSetChanged处理程序执行,然后进行元数据调用,最后再重新创建每个View。


我们可以看到,观察者模式非常适合在GUI中解耦界面元素和Model。设想如果不是使用观察者模式,界面元素可能要采用轮询的方式去检查Model有没有变化,这样效率就相当低下了。

又设想如果Model直接针对具体的界面元素类发消息,通知界面Model发生了变化,那么这部分的代码就没法应用到别的界面类,而界面类也很难在运行时动态替换相关联的Model。所以在界面元素类和Model顶部我们又抽象出观察者和被观察者两个抽象接口,而且用组合的方式建立两者的关系,这就将二者完全解耦了--界面可以在运行时替换自己的ModelModel也可以在运行时删除或增加和自己对应的界面类。

如果我们将View和Modle之间的交互过程进一步封装到一个中介者,即把两者的通信都集中在Controller中,就变成了接下来要讲的MVC模式。Controller进一步分割了View和Modle的职责,体现了单一职责原则。

3.MVC (Model-View-Controller)

(1)M是指逻辑模型,V是指视图模型,C则是控制器。一个逻辑模型可以对于多种视图模型,比如一批统计数据你可以分别用柱状图、饼图来表示。一种视图模型也可以对于多种逻辑模型。使用MVC的目的是将M和V的实现代码分离,从而使同一个程序可以使用不同的表现形式,而C存在的目的则是确保M和V的同步,一旦M改变,V应该同步更新。

MVC 基本处理流程 如下:

用户与视图交互,视图接爱并反馈用户的动作;视图把用户的请求传给相应的控制器,由控制器决定调用哪个模型,然后由模型调用相应的业务逻辑对用户请求进行加工处理,如果需要返回数据,模型会把相应的数据返回给控制器,由控制器调用相应的视图,最终由视图格式化和渲染返回的数据,对于返回的数据完全可以增加用户体验效果展现给用户。

       Android中界面部分也采用了当前比较流行的MVC框架,在Android中: 

  1) 视图层(View):一般采用XML文件进行界面的描述,使用的时候可以非常方便的引入。当然,如何你对Android了解的比较的多了话,就一定可以想到在Android中也可以使用JavaScript+HTML等的方式作为View层,当然这里需要进行Java和JavaScript之间的通信,幸运的是,Android提供了它们之间非常方便的通信实现。     

  2) 控制层(Controller):Android的控制层的重任通常落在了众多的Acitvity的肩上,这句话也就暗含了不要在Acitivity中写代码,要通过Activity交割Model业务逻辑层处理,这样做的另外一个原因是Android中的Acitivity的响应时间是5s,如果耗时的操作放在这里,程序就很容易被回收掉。

  3) 模型层(Model):对数据库的操作、对网络等的操作都应该在Model里面处理,当然对业务计算等操作也是必须放在的该层的。就是应用程序中二进制的数据。

总结来说,xml布局文件是view相当于JSP页面; activity和intent起到了controller的作用; provider对数据层做了良好的封装,而且provider把数据管理的范畴从数据库泛化到了数据的概念,不光管理数据记录,只要是数据文件(图片、视频、声音文件、所有其他的一切的file)都纳入管理,且提供了数据共享的机制,这是比较出彩的地方; broadcastreceiver提供了一种良好的消息机制,使得一个应用不再是一个信息孤岛,而是和其他的应用、服务等构成了信息网络,从而极大的丰富了应用的开发空间,给了应用开发者极大的想象创造的可能。

(2)那么究竟该如何划分这几层结构呢?我觉得可以换个思路出发,我们究竟该如何合理地组织一个Android应用程序呢?我们不必教条地、具有成见地将原先系统划分结构带入到这样一个新的框架结构中,而是需要在这个特定结构中发挥其框架的效果:

1)xml布局负责将界面布局做好,并且尽量做到合理分割与减少层次

2)Activity做好控件事件绑定与业务流程控制

3)Intent做好Activity间的session传递管理

4)自己创建Model(可以通过Observer模式进行绑定处理、并且包装好各种provider)将处理数据的工作做好。不建议简单地将各个数据字段散乱地存放在Activity周围,而是借助数据Bean的思路存放在Model下面,这样在Model数据项变得庞大后难于管理与重构,而且这多为非面对对象的设计方案。

5)Adapter是数据与呈现的粘合剂。Adapter是Model和View中的桥梁,就是 Controller。

这篇文章演示了怎么通过观察者模式分离Activity和Model:http://www.cnblogs.com/lee0oo0/p/3179585.html
这篇文章也讲解了android中的MVC:http://blog.csdn.net/sylcc_/article/details/7346149

4.代理模式

(1)定义:为其他对象提供一种代理以控制对这个对象的访问。
(2)例子:
在使用aidl service时,在客户端代码绑定远端service之后会获得本地代理,该代理实现了aidl接口,但是函数调用是通过binder驱动转发给远端的实际服务类的。关键一点是代理类和实际的服务类实现了同一个接口, 那么客户代码就可以像使用实际服务类一样使用代理类。

5.Template Method

(1)定义算法的骨架,而将一些步骤延迟到子类中。TemplateMethod使得子类不改变一个算法的结构即可重定义该算法的某些步骤。
(2)TemplateMethod使用继承改变算法的一部分,也是经常使用的一个模式。继续用getWritableDatabase作为例子:
public abstract class SQLiteOpenHelper {
 public synchronized SQLiteDatabase getWritableDatabase() {
  	……
        boolean success = false;
        SQLiteDatabase db = null;
        if (mDatabase != null) mDatabase.lock();
        try {
            mIsInitializing = true;
            if (mName == null) {
                db = SQLiteDatabase.create(null);
            } else {
                db = mContext.openOrCreateDatabase(mName, 0, mFactory, mErrorHandler);
            }

            int version = db.getVersion();
            if (version != mNewVersion) {
                db.beginTransaction();
                try {
                    if (version == 0) {
                       onCreate(db);
		    } else {
                        if ( mNewVersion) {
                           onDowngrade(db, version, mNewVersion);
                        } else {
			   onUpgrade(db, version, mNewVersion);
			}
                    }
                    db.setVersion(mNewVersion);
                    db.setTransactionSuccessful();
                } finally {
                    db.endTransaction();
                }
            }

            onOpen(db);
	……            
 }

 public abstract void onCreate(SQLiteDatabase db);
 public abstract void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion);
 public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        throw new SQLiteException("Can't downgrade database from version " +
                oldVersion + " to " + newVersion);
 }
 public void onOpen(SQLiteDatabase db) {}
}
getWritableDatabase()是一个典型的TemplateMethod,子类通过override onCreate、onUpgrade、onDowngrade、onOpen可以定制自己在创建、打开数据库是的具体操作,在父类中则定义了算法的框架,通过调用抽象函数或者提供了默认操作但可被覆写的函数,使得子类可以重定义这些操作以提供具体的行为。onOpen()是一个hook operation,提供了一个空操作的缺省行为,子类可以进行扩展。
模版方法体现了依赖倒置原则:
1)高层模块不应该依赖于低层模块,二者都依赖于抽象。
2)抽象不依赖于细节,细节应依赖于抽象。
模版方法常用于重构当中,当几个功能相近的类有部分公共代码时,可以把公共代码抽出来作为父类,定义一些模版方法让子类覆写,可减少重复代码。

再看一个例子。当我们使用IntentService时,会覆写onHandleIntent(),一旦收到请求,onHandleIntent处理程序就会在一个工作线程中执行。
private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            onHandleIntent((Intent)msg.obj);
            stopSelf(msg.arg1);
        }
    }

其中ServiceHandle是在IntentService的onCreate方法创建的,负责在工作线程中处理我们的intent。注意到,ServiceHandle的handleMessage是一个模版方法,该方法调用了开发者将会override的onHandleIntent,并在处理完之后终止自己。因为ServiceHandle是IntentService的一个内部类,持有外部类IntentService对象的引用,因此可以调用IntentService的抽象方法onHandleIntent。可以看到TemplateMethod非常适合用于构建框架。

6.Builder(生成器)

(1)定义:将一个复杂对象的构建和他的表示分离,使得同样的构建过程可以创建不同的表示。
(2)例子
AlertDialog.Builder builder = new AlertDialog.Builder(this)
    	.setTitle("Test")
    	.setIcon(R.drawable.ic_launcher)
    	.setMessage("Test");
builder.create().show();
AlertDialog.Builder是典型的Builder模式。AlertDialog具有复杂的构造参数,如果直接在AlertDialog的构造函数传入这些参数,AlertDialog的构造函数会变得过于复杂而难以使用,而且不是所有代码都需要全部的构造参数,这样又会导致很多的重载构造函数。如果把这些参数都包装成一个对象(在Builder中也是这样)给开发者使用,又暴露了AlertDialog的内部实现。
所以在这里Builder模式
1)将构造代码和表示代码分开。Builder模式通过封装AlertDialog的创建和表示过程,提高了对象的模块性。将创建和装配对象的代码都封装在AlertDialog.Builder当中,符合单一职责原则。
2)使得开发者可以对构造过程进行更精细的控制。不同参数的构建,对象的创建,现实AlertDialog,都分布在不同的函数接口中,在封装内部实现的同时,给予了开发者控制AlertDialog的最大自由度。

Android3.0中引入的NotificationBuilder简化了配置Notification的标志、选项、内容和布局的过程,是较新平台构造Notification的首选方式。可以看到Builder模式适合于构建具有复杂表示的GUI组件。
Notification.Builder builder = 
      new Notification.Builder(MyActivity.this);

    builder.setSmallIcon(R.drawable.ic_launcher)
           .setTicker("Notification")
           .setWhen(System.currentTimeMillis())
           .setDefaults(Notification.DEFAULT_SOUND |
                        Notification.DEFAULT_VIBRATE)
           .setSound(
              RingtoneManager.getDefaultUri(
                RingtoneManager.TYPE_NOTIFICATION))
           .setVibrate(new long[] { 1000, 1000, 1000, 1000, 1000 })
           .setLights(Color.RED, 0, 1);

    Notification notification = builder.getNotification();

7.组合设计模式

1.定义:
将对象组合成树形结构以表示“部分-整体”的层次结构。Composite使得用户对单个对象和组合对象的使用具有一致性。
2.View和ViewGroup是典型的组合设计模式。界面中的组件组成一颗view树,当需要更新界面时,peformTraversals过程会遍历view树。在这里,组合设计模式能够支持以统一的方式遍历view树。当然,ViewGroup也另外实现了两个接口:ViewParent和ViewManager,这两个接口突出表示了ViewGroup作为Composite承担了更多的职责,而View作为Leaf是遍历的终止点。
另外,当View需要更新UI时,它会通过invalidate或者其他方式发起请求。随后这些请求会沿着ViewTree层次上传,最终到达ViewRoot。这相当于从叶子节点向根节点传递消息。

8.后记

一直想写一篇总结Android设计模式的文章,苦于水平不足迟迟没有下笔。最近看完Martin的《敏捷软件开发》感觉对设计模式的理解又加深了一些,把一些思考写下来。肯定有不足的地方,欢迎大家指导。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陆业聪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值