设计模式之观察者模式---Observer Pattern

来源:互联网 发布:caffe loss大小 编辑:程序博客网 时间:2024/05/22 09:04

模式的介绍

模式的定义

观察者模式(Observer Pattern)也叫发布订阅模式(Publish\subscribe),定义如下:
Define a one-to-many dependency between objects so that when one object changes state,all its dependents are notified and updated automatically.

定义对象间的一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。

模式的使用场景

  • 关联行为场景
  • 事件多级触发场景
  • 跨系统的消息交换场景,如消息队列的处理机制

UML类图

这里写图片描述

角色介绍

  • Observer 观察者

定义了观察者更新的操作方法update

  • Subject 被观察者

定义了观察者的注册,注销接口和被观察者变化的通知接口

  • ConcreteObserver 具体的观察者
  • ConcreteSubject 具体的被观察者
    主要是实现了注册,注销和通知数据更新的三个接口,其中的一个关键变量-List concreteObserver,这个变量主要是对所有的观察者进行管理,当数据改变时,遍历所有的观察者,进行相对应的操作。

模式的简单实现

抽象观察者类 Observer :
定义了一个更新操作的接口

public  interface Observer {    public void update();   }

具体的观察者 ConcreteObserver:
实现了update更新操作

public class ConcreteObserver implements Observer{    @Override    public void update() {        // TODO Auto-generated method stub        System.out.println("we receive message, do update!");    }}

抽象被观察者类 Subject :
关键是定义注册(register),反注册(unregister),内容改变的通知(notifyObservers)三个方法和观察者的集合变量(Vector observers)。

import java.util.Vector;public abstract class Subject {    private Vector<Observer> observers = new Vector<Observer>();    public void register(Observer observer){        if(!observers.contains(observer)){            observers.add(observer);        }           }    public void unregister(Observer observer){        if(observers.contains(observer)){            observers.remove(observer);        }           }    public void notifyObservers(){        for(Observer o:observers){                      o.update();        }    }}

具体观察者 ConcreteSubject :

public class ConcreteSubject extends Subject{    public void doSomething(){        super.notifyObservers();    }}

Main方法:

    public static void main(String[] args) {        ConcreteSubject concreteSubject = new ConcreteSubject();        Observer observer = new ConcreteObserver();        concreteSubject.register(observer);        concreteSubject.doSomething();    }

程序输出:

we receive message, do update!

模式的综合样例

对于学校的学生来说,上课铃声响后,学生要上课听讲,老师的上课教书,这是非常熟悉的。其实,这就是一个非常经典的观察者模式(一对多)。
先来看一下我们的类图:
这里写图片描述

我们定义一个观察者的接口Observer:

public interface Observer {     public void update();}

然后对应的定义二个观察者学生(Student),老师(Teacher),实现其Observer接口。

public class Student implements Observer {    @Override    public void update() {        // TODO Auto-generated method stub        System.out.println("上课铃声响了,又要听这个老师xxxxxxxx…………");    }}
public class Teacher implements Observer{    @Override    public void update() {        // TODO Auto-generated method stub        System.out.println("上课铃声响了,又要给这帮孩子…………xxxxxxxx");    }}

我们再定义被观察者的接口Observable :

public interface Observable {    public void register(Observer oberver);    public void unregister(Observer oberver);    public void notifyDate();}

再综合单例模式定义一个被观察者铃声类Ringtone ,实现Observable 接口:

import java.util.Vector;public class Ringtone implements Observable{    private static Ringtone ringtone  = new Ringtone();    public static Vector<Observer> observers = new Vector<Observer>();    private Ringtone(){    }    public static final Ringtone getRingtoneSinglone(){        return ringtone;    }    @Override    public void register(Observer oberver) {        // TODO Auto-generated method stub        if(!observers.contains(oberver)){            observers.add(oberver);        }    }    @Override    public void unregister(Observer oberver) {        // TODO Auto-generated method stub        if(observers.contains(oberver)){            observers.remove(oberver);        }    }    @Override    public void notifyDate() {        // TODO Auto-generated method stub        for(Observer observer:observers){            observer.update();        }    }    public void ring(){        System.out.println("上课铃声响了!!");        notifyDate();    }}

Main:

public static void main(String[] args) {        // TODO Auto-generated method stub        Ringtone ringtone = Ringtone.getRingtoneSinglone();        Observer student = new Student();        Observer teacher = new Teacher();        ringtone.register(teacher);        ringtone.register(student);        ringtone.ring();}

程序输出:

上课铃声响了!!上课铃声响了,又要给这帮孩子…………xxxxxxxx上课铃声响了,又要听这个老师xxxxxxxx…………

模式的优缺点

优点

  • 观察者和被观察者之间是抽象耦合
  • 建立一套触发机制

缺点

观察者模式需要考虑开发效率和运行效率。一个被观察者,多个观察者,开发和调试比较复杂,而且java中消息的通知默认是顺序执行,一个观察者卡壳,会影响整体的执行效率。在这种情况下,一般考虑异步的方式。

多级触发的效率更是让人担忧,大家设计时要注意考虑。

Android源码中的模式实现

BroadcastReceiver

在android开发时,我们经常定义一个新的广播(观察者),

import android.content.BroadcastReceiver;  import android.content.Context;  import android.content.Intent;  public class MyReceiver extends BroadcastReceiver {      @Override      public void onReceive(Context context, Intent intent) {          String msg = intent.getStringExtra("msg");          ..............    }  }

然后注册,有二种方式:
(1)静态注册
在androidManifest.xml中注册:

<receiver android:name=".MyReceiver">     <intent-filter>        <action android:name="android.intent.action.MY_BROADCAST"/>        <category android:name="android.intent.category.DEFAULT" />     </intent-filter>  </receiver> 

(2)代码动态注册

MyReceiver receiver = new MyReceiver();            IntentFilter filter = new IntentFilter();  filter.addAction("android.intent.action.MY_BROADCAST");          registerReceiver(receiver, filter);  

对应的反注册的方式:

protected void onDestroy() {      super.onDestroy();      unregisterReceiver(receiver);  }  

当我们发送对应的Intent时,

Intent intent = new Intent("android.intent.action.MY_BROADCAST");  intent.putExtra("msg", "hello receiver.");  sendBroadcast(intent);  

对应的MyReceiver会执行onReceive方法,更新对应的操作。

从上面的使用过程,我们可以清楚的看到:
MyReceiver做为具体的观察者(ConcreteObserver),我们只需要实现其onReceive的更新方法。

BroadcastReceiver 做为抽象观察者(Observer)。
在android源码中:

./frameworks/base/core/java/android/content/BroadcastReceiver.java

看到:

//抽象类 BroadcastReceiver,做为Observerpublic abstract class BroadcastReceiver {    ............    //定义抽象更新方法onReceive    public abstract void onReceive(Context context, Intent intent);    ............}

在当前Context中,例如Activity,相当于具体的被观察者类,我们调用:
registerReceiver方法注册
unregisterReceiver方法反注册
sendBroadcast方法通知被观察者已经改变,观察者调用onReceive方法更新。

Activity的类:
这里写图片描述

Context类相当于Subject 抽象的被观察者.
在android的源码中:

./frameworks/base/core/java/android/content/Context.java

关键方法:

//抽象被观察者类 Contextpublic abstract class Context {.............    //注册方法 registerReceiver    public abstract Intent registerReceiver(@Nullable BroadcastReceiver receiver,IntentFilter filter);    public abstract Intent registerReceiver(BroadcastReceiver receiver,IntentFilter filter, @Nullable String broadcastPermission,@Nullable Handler scheduler);    //反注册方法 unregisterReceiver    public abstract void unregisterReceiver(BroadcastReceiver receiver);    //通知被观察者改变的方法 sendBroadcast    public abstract void sendBroadcast(Intent intent);    public abstract void sendBroadcast(Intent intent, @Nullable String receiverPermission);    public abstract void sendBroadcast(Intent intent,String receiverPermission, int appOp);...............}

中间类ContextWrapper :

./frameworks/base/core/java/android/content/ContextWrapper.java
public class ContextWrapper extends Context {    Context mBase;    //构造方法    public ContextWrapper(Context base) {        mBase = base;    }..........    //注册方法 registerReceiver    public Intent registerReceiver(        BroadcastReceiver receiver, IntentFilter filter) {        return mBase.registerReceiver(receiver, filter);    }    public Intent registerReceiver(        BroadcastReceiver receiver, IntentFilter filter,        String broadcastPermission, Handler scheduler) {        return    mBase.registerReceiver(receiver,filter,broadcastPermission,scheduler);    }    /** @hide */    @Override    public Intent registerReceiverAsUser(        BroadcastReceiver receiver, UserHandle user, IntentFilter filter,        String broadcastPermission, Handler scheduler) {        return mBase.registerReceiverAsUser(receiver, user,filter, broadcastPermission,scheduler);    }    //反注册方法 unregisterReceiver    @Override    public void unregisterReceiver(BroadcastReceiver receiver) {        mBase.unregisterReceiver(receiver);    }    //通知被观察者改变的方法 sendBroadcast    @Override    public void sendBroadcast(Intent intent) {        mBase.sendBroadcast(intent);    }    @Override    public void sendBroadcast(Intent intent, String receiverPermission) {        mBase.sendBroadcast(intent, receiverPermission);    }    /** @hide */    @Override    public void sendBroadcast(Intent intent, String receiverPermission, int appOp) {        mBase.sendBroadcast(intent, receiverPermission,appOp);    }    ...............}

从代码来看,ContextWrapper 类实现了Conext类,在对应的重写方法中,只是调用了mBase变量的对应方法。

那么实现registerReceiver,unregisterReceiver,sendBroadcast三个方法的是类ContextImpl

./frameworks/base/core/java/android/app/ContextImpl.java
/** * Common implementation of Context API, which provides the base * context object for Activity and other application components. */class ContextImpl extends Context {................    //实现注册方法 registerReceiver    @Override    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {        return registerReceiver(receiver, filter, null, null);    }    @Override    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,            String broadcastPermission, Handler scheduler) {        return registerReceiverInternal(receiver, getUserId(),                filter, broadcastPermission, scheduler, getOuterContext());    }    @Override    public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user,            IntentFilter filter, String broadcastPermission, Handler scheduler) {        return registerReceiverInternal(receiver, user.getIdentifier(),                filter, broadcastPermission, scheduler, getOuterContext());    }    private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,            IntentFilter filter, String broadcastPermission,            Handler scheduler, Context context) {        IIntentReceiver rd = null;        if (receiver != null) {            if (mPackageInfo != null && context != null) {                if (scheduler == null) {                    scheduler = mMainThread.getHandler();                }                rd = mPackageInfo.getReceiverDispatcher(                    receiver, context, scheduler,                    mMainThread.getInstrumentation(), true);            } else {                if (scheduler == null) {                    scheduler = mMainThread.getHandler();                }                rd = new LoadedApk.ReceiverDispatcher(                        receiver, context, scheduler, null, true).getIIntentReceiver();            }        }        try {            return ActivityManagerNative.getDefault().registerReceiver(                    mMainThread.getApplicationThread(), mBasePackageName,                    rd, filter, broadcastPermission, userId);        } catch (RemoteException e) {            return null;        }    }    //反注册方法 unregisterReceiver    @Override    public void unregisterReceiver(BroadcastReceiver receiver) {        if (mPackageInfo != null) {            IIntentReceiver rd = mPackageInfo.forgetReceiverDispatcher(                    getOuterContext(), receiver);            try {                ActivityManagerNative.getDefault().unregisterReceiver(rd);            } catch (RemoteException e) {            }        } else {            throw new RuntimeException("Not supported in system context");        }    }    //通知被观察者改变的方法 sendBroadcast    @Override    public void sendBroadcast(Intent intent) {        warnIfCallingFromSystemProcess();        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());        try {            intent.prepareToLeaveProcess();            ActivityManagerNative.getDefault().broadcastIntent(                mMainThread.getApplicationThread(), intent, resolvedType, null,                Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, false, false,                getUserId());        } catch (RemoteException e) {        }    }    @Override    public void sendBroadcast(Intent intent, String receiverPermission) {        warnIfCallingFromSystemProcess();        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());        try {            intent.prepareToLeaveProcess();            ActivityManagerNative.getDefault().broadcastIntent(                mMainThread.getApplicationThread(), intent, resolvedType, null,                Activity.RESULT_OK, null, null, receiverPermission, AppOpsManager.OP_NONE,                false, false, getUserId());        } catch (RemoteException e) {        }    }    @Override    public void sendBroadcast(Intent intent, String receiverPermission, int appOp) {        warnIfCallingFromSystemProcess();        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());        try {            intent.prepareToLeaveProcess();            ActivityManagerNative.getDefault().broadcastIntent(                mMainThread.getApplicationThread(), intent, resolvedType, null,                Activity.RESULT_OK, null, null, receiverPermission, appOp, false, false,                getUserId());        } catch (RemoteException e) {        }    }................}

可以看到ContextImpl实现registerReceiver,unregisterReceiver,sendBroadcast这三个方法是依靠:

//注册ActivityManagerNative.getDefault().registerReceiver//反注册ActivityManagerNative.getDefault().unregisterReceiver(rd)//广播ActivityManagerNative.getDefault().broadcastIntent

我们查看ActivityManagerNative类:

./frameworks/base/core/java/android/app/ActivityManagerNative.java
public abstract class ActivityManagerNative extends Binder implements IActivityManager{.................    /**     * Retrieve the system's default/global activity manager.     * 返回一个IActivityManager     */    static public IActivityManager getDefault() {        return gDefault.get();    }.................    //通过IBinder ,返回IActivityManager    private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {        protected IActivityManager create() {            IBinder b = ServiceManager.getService("activity");            if (false) {                Log.v("ActivityManager", "default service binder = " + b);            }            IActivityManager am = asInterface(b);            if (false) {                Log.v("ActivityManager", "default service = " + am);            }            return am;        }    };    //注册    public Intent registerReceiver(IApplicationThread caller, String packageName,            IIntentReceiver receiver,            IntentFilter filter, String perm, int userId) throws RemoteException    {        Parcel data = Parcel.obtain();        Parcel reply = Parcel.obtain();        data.writeInterfaceToken(IActivityManager.descriptor);        data.writeStrongBinder(caller != null ? caller.asBinder() : null);        data.writeString(packageName);        data.writeStrongBinder(receiver != null ? receiver.asBinder() : null);        filter.writeToParcel(data, 0);        data.writeString(perm);        data.writeInt(userId);        mRemote.transact(REGISTER_RECEIVER_TRANSACTION, data, reply, 0);        reply.readException();        Intent intent = null;        int haveIntent = reply.readInt();        if (haveIntent != 0) {            intent = Intent.CREATOR.createFromParcel(reply);        }        reply.recycle();        data.recycle();        return intent;    }    //反注册    public void unregisterReceiver(IIntentReceiver receiver) throws RemoteException    {        Parcel data = Parcel.obtain();        Parcel reply = Parcel.obtain();        data.writeInterfaceToken(IActivityManager.descriptor);        data.writeStrongBinder(receiver.asBinder());        mRemote.transact(UNREGISTER_RECEIVER_TRANSACTION, data, reply, 0);        reply.readException();        data.recycle();        reply.recycle();    }   //广播       public int broadcastIntent(IApplicationThread caller,            Intent intent, String resolvedType,  IIntentReceiver resultTo,            int resultCode, String resultData, Bundle map,            String requiredPermission, int appOp, boolean serialized,            boolean sticky, int userId) throws RemoteException    {        Parcel data = Parcel.obtain();        Parcel reply = Parcel.obtain();        data.writeInterfaceToken(IActivityManager.descriptor);        data.writeStrongBinder(caller != null ? caller.asBinder() : null);        intent.writeToParcel(data, 0);        data.writeString(resolvedType);        data.writeStrongBinder(resultTo != null ? resultTo.asBinder() : null);        data.writeInt(resultCode);        data.writeString(resultData);        data.writeBundle(map);        data.writeString(requiredPermission);        data.writeInt(appOp);        data.writeInt(serialized ? 1 : 0);        data.writeInt(sticky ? 1 : 0);        data.writeInt(userId);        mRemote.transact(BROADCAST_INTENT_TRANSACTION, data, reply, 0);        reply.readException();        int res = reply.readInt();        reply.recycle();        data.recycle();        return res;    }//关键变量,处理跨应用的数据传输 private IBinder mRemote;}

我们可以看出ActivityManagerNative类中registerReceiver,unregisterReceiver,broadcastIntent三个方法主要是调用mRemote.transact方法。mRemote是IBinder 变量,所以我们能理解,为什么广播是跨应用。

参考资料

(1).设计模式之禅—第22章 观察者模式

0 0