1. 程式人生 > >觀察者模式解析

觀察者模式解析

xtend 實時 message sendto 監聽器 style fin 設計 tcl

一、觀察者模式概述

觀察者模式(有時又被稱為模型-視圖(View)模式、源-收聽者(Listener)模式或從屬者模式)是軟件設計模式的一種。在此種模式中,一個目標物件管理所有相依於它的觀察者物件,並且在它本身的狀態改變時主動發出通知。這通常透過呼叫各觀察者所提供的方法來實現。此種模式通常被用來實現事件處理系統。

觀察者模式主要由以下四個部分組成:

1) 抽象目標角色(Subject):目標角色知道它的觀察者,可以有任意多個觀察者觀察同一個目標。並且提供註冊和刪除觀察者對象的接口。目標角色往往由抽象類或者接口來實現。

2) 抽象觀察者角色(Observer):為那些在目標發生改變時需要獲得通知的對象定義一個更新接口。抽象觀察者角色主要由抽象類或者接口來實現。

3) 具體目標角色(Concrete Subject):將有關狀態存入各個Concrete Observer對象。當它的狀態發生改變時, 向它的各個觀察者發出通知。

4) 具體觀察者角色(Concrete Observer):存儲有關狀態,這些狀態應與目標的狀態保持一致。實現Observer的更新接口以使自身狀態與目標的狀態保持一致。在本角色內也可以維護一個指向Concrete Subject對象的引用。

技術分享圖片

觀察者模式符合接口隔離原則,實現了對象之間的松散耦合,其UML圖示如下:

技術分享圖片

二、為什麽使用觀察者模式

觀察者模式在實際項目中使用的也是非常頻繁的,它最常用的地方是GUI系統、訂閱——發布系統等。因為這個模式的一個重要作用就是解耦,使得它們之間的依賴性更小,甚至做到毫無依賴。以GUI系統來說,應用的UI具有易變性,尤其是前期隨著業務的改變或者產品的需求修改,應用界面也經常性變化,但是業務邏輯基本變化不大,此時,GUI系統需要一套機制來應對這種情況,使得UI層與具體的業務邏輯解耦,觀察者模式此時就派上用場了。觀察者模式又被稱作發布/訂閱模式,觀察者模式定義了一種一對多的依賴關系,讓多個觀察者對象同時監聽某一個主題對象。這個主題對象在狀態發生變化時,會通知所有觀察者對象,使它們能夠自動更新自己。

應用示例:

介紹

  • 這是一個用於攔截android實時短信的庫,可以進行短信過濾,得到自己想要的內容,可以用於需要自動填寫短信驗證碼的app項目

功能

  • 用於監聽當前接收到的短信信息
  • 過濾接收到的短信,得到自己想要的內容

首先定義觀察者類SmsObserver,包括應用於觀察者的一系列方法:

 public class SmsObserver extends ContentObserver {
    private Context mContext;
    public static final int MSG_RECEIVED_CODE = 1001;
    private SmsHandler mHandler;

    
/*** *定義三種不同的觀察者構造方法 */ public SmsObserver(Activity context, SmsResponseCallback callback,SmsFilter smsFilter) { this(new SmsHandler(callback,smsFilter)); this.mContext = context; } public SmsObserver(Activity context, SmsResponseCallback callback) { this(new SmsHandler(callback)); this.mContext = context; } public SmsObserver(SmsHandler handler) { super(handler); this.mHandler = handler; } /*** * 設置短信過濾器 * @param smsFilter */ public void setSmsFilter(SmsFilter smsFilter) { mHandler.setSmsFilter(smsFilter); } /*** * 註冊短信變化觀察者的方法 */ public void registerSMSObserver() { Uri uri = Uri.parse("content://sms"); if (mContext != null) { mContext.getContentResolver().registerContentObserver(uri, true, this); } } /*** * 註銷短信變化觀察者的方法 */ public void unregisterSMSObserver() { if (mContext != null) { mContext.getContentResolver().unregisterContentObserver(this); } if (mHandler != null) { mHandler = null; } } /*** * 設置短信變化的時候發送狀態給觀察者的方法 */ @Override public void onChange(boolean selfChange, Uri uri) { super.onChange(selfChange, uri); if (uri.toString().equals("content://sms/raw")) { return; } Uri inboxUri = Uri.parse("content://sms/inbox");//收件箱 try { Cursor c = mContext.getContentResolver().query(inboxUri, null, null, null, "date desc"); if (c != null) { if (c.moveToFirst()) { String address = c.getString(c.getColumnIndex("address")); String body = c.getString(c.getColumnIndex("body")); if (mHandler != null) { mHandler.obtainMessage(MSG_RECEIVED_CODE, new String[]{address, body}) .sendToTarget(); } Log.i(getClass().getName(), "發件人為:" + address + " " + "短信內容為:" + body); } c.close(); } } catch (SecurityException e) { Log.e(getClass().getName(), "獲取短信權限失敗", e); } catch (Exception e) { e.printStackTrace(); } } }

初始化觀察者實例:

SmsObserver smsObserver=new SmsObserver(this, new SmsResponseCallback() {
                 @Override
                 public void onCallbackSmsContent(String smsContent) {
                     //這裏接收短信
                 }
             }, new VerificationCodeSmsFilter("180"));

註冊短信變化監聽器

  • 在註冊監聽器以後,短信觀察者就已經啟動短信變化監聽,接下只要接收短信,對短信做處理就可以了
public void registerSMSObserver() {
        Uri uri = Uri.parse("content://sms");
        if (mContext != null) {
            mContext.getContentResolver().registerContentObserver(uri,
                    true, this);
        }
    }
   smsObserver.registerSMSObserver();

註銷短信變化監聽器

  • 在不需要再使用短信接收功能的時候,請註銷短信監聽器,不然後續還是可以接收得到短信
/***
     * 註銷短信變化觀察者
     */
    public void unregisterSMSObserver() {
        if (mContext != null) {
            mContext.getContentResolver().unregisterContentObserver(this);
        }
        if (mHandler != null) {
            mHandler = null;
        }
    }
   smsObserver.unregisterSMSObserver();

觀察者模式解析