观察者模式解析

Posted astrobin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了观察者模式解析相关的知识,希望对你有一定的参考价值。

一、观察者模式概述

观察者模式(有时又被称为模型-视图(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();

 

 

以上是关于观察者模式解析的主要内容,如果未能解决你的问题,请参考以下文章

设计模式 行为型模式 -- 观察者模式(发布-订阅(Publish/Subscribe)模式)

观察者模式解析

设计模式课程 设计模式精讲 21-3 观察者模式源码解析

观察者模式解析

chromium中的观察者模式解析

银行办理业务观察者模式解析