标签:
这篇来讲一下观察者模式,观察者模式在实际项目中使用的也是非常频繁的,它最常用的地方是GUI系统、订阅——发布系统等。因为这个模式的一个重要作用就是解耦,使得它们之间的依赖性更小,甚至做到毫无依赖。以GUI系统来说,应用的UI具有易变性,尤其是前期随着业务的改变或者产品的需求修改,应用界面也经常性变化,但是业务逻辑基本变化不大,此时,GUI系统需要一套机制来应对这种情况,使得UI层与具体的业务逻辑解耦,观察者模式此时就派上用场了。
PS:对技术感兴趣的同鞋加群544645972一起交流。
观察者模式定义了对象之间的一对多依赖,这样一来,当一个对象状态发生改变时,它的所有依赖者都会收到通知并自动更新。它实现了 Subject 和 Observer 之间的松耦合,Subject只知道观察者实现了 Observer 接口,主题不需要知道具体的类是谁、做了些什么或其他任何细节。任何时候我们都可以增加新的观察者。因为主题唯一依赖的东西是一个实现Observer 接口的对象列表,所以我们可以随时增加观察者,同样的,也可以在任何时候删除观察者,当然更不用去关心观察者的类型,只要实现了Observer接口即可,Subject 最后只会发通知给实现了 Observer 接口的观察者。Subject 和 Observer 之间实现松耦合之后,双方代码的修改都不会影响到另外一方,当然前提是双方得遵守接口的规范(接口隔离原则)。
观察者模式使用的场景:
观察者模式的uml类图如上图所示,一般基本由4个角色构成
观察者模式写法有很多种,只要遵循将被观察者和观察者解耦思想的方法都是可以的,列举三种我在开发中常见的方法,以 firstmoduel 作为 secondmodule1 和 secondmodule2 的父 module ,最后 application 以 secondmoduel1 和secondmodule2 作为父 module,形成一个菱形的关系为例:
使用Java API的写法其实就是使用 java.util.Observable 类和 java.util.Observer 接口,根据 uml 类图构造观察者,我们简单实现一个在 secondmodule2 中通知 secondmodule1有数据源的改变,并且让 secondmodule1 打印出对应日志的功能。因为 secondmodule1 和 secondmodule2 是一个同级关系,所以无法相互调用,只能通过 firstmodule 作为主题使用观察者模式进行通信。
Subject 在使用 Java API 时其实就是 Observable 类,所以我们要在 firstmodule 中继承该类实现一个 ConcreteSubject 用来保存所有的观察者,接着在 secondmodule1 中实现 Observer 接口来生成一个观察者,最后在secondmodule2 中通知 firstmodule 数据源改变,最后通过 firstmodule 通知到 secondmodule1 ,代码如下:
firstmoduel/DataObservable.class 中利用单例模式进行观察者的管理和通知:
public class DataObservable extends Observable{
private static volatile DataObservable instance;
private DataObservable() {}
public static DataObservable getInstance() {
if (instance == null){
synchronized (DataObservable.class) {
if (instance == null){
instance = new DataObservable();
}
}
}
return instance;
}
public void notifyDataChanged(DataBean data) {
setChanged();
notifyObservers(data);
}
}
firstmoduel/DataBean.class 数据类:
public class DataBean {
public int temperature;
}
secondmodule1/DataObserver.class 中判断如果为正确的 Observerable 则打印日志:
public class DataObserver implements Observer {
private static final String TAG = "DataObserver";
@Override
public void update(Observable observable, Object data) {
if (observable instanceof DataObservable){
if (data instanceof DataBean){
Log.e(TAG, ((DataBean)data).temperature+"");
}
}
}
}
secondmodule2/DataNotify.class
public class DataNotify {
public static void notifyDataChanged(){
DataBean bean = new DataBean();
bean.temperature = (int) (Math.random() * 40);
DataObservable.getInstance().notifyDataChanged(bean);
}
}
最后在 MainActivity 中调用 DataNotify 类的相应方法通知 DataObserver 温度数据变更即可:
@Override
protected void onCreate(Bundle savedInstanceState) {
...
DataObservable.getInstance().addObserver(new DataObserver());
}
@Override
protected void onDestroy() {
super.onDestroy();
DataObservable.getInstance().deleteObserver(new DataObserver());
}
...
public void onClick(View v) {
if (v.getId() == R.id.btn_data_change_1){
DataNotify.notifyDataChanged();
}
...
}
最后能够成功打印出正确日志,也就是实现了 android 中两个同级 module 之间的通信。
当然如果觉得麻烦不使用 Java API 的这两个类,自己去实现的话也是完全可以的,而且有时可操纵性会比 Java API 更好一些。
有时候我们不一定全部要实现自同一个 Observer 接口,根据实际情况我们可以在完全解耦的情况下将多个 Observer 注册到 Subject 中,并且根据情况只通知到我们想要通知的一个 Observer 中,听起来很乱,其实看一张 uml 图就清楚了:
这种方式其实最重要的就是 Subject 这个角色了,他承担了大部分的工作量,我们先实现若干个 Observer 的角色:
firstmodule/IDataListenerOne.class
public interface IDataListenerOne {
void OnDataChanged(DataBean data);
}
firstmodule/IDataListenerTwo.class
public interface IDataListenerTwo {
void OnDataChanged(DataBean data);
}
非常简单的几个接口,用来在 secondmodule1 和 secondmodule2 之间进行通信。接着是最重要的 Subject 和 ConcreteSubject 角色:
firstmodule/IMultiDataObservable.class
public interface IMultiDataObservable {
/**
* 增加观察者
*/
void addObserver(Object observer);
/**
* 删除观察者
*/
void deleteObserver(Object observer) throws IllegalArgumentException;
/**
* 查找观察者
*/
<T>ArrayList<T> findObserver(Class<T> clazz);
}
firstmodule/MultiDataObservable.class
public class MultiDataObservable implements IMultiDataObservable {
private static volatile MultiDataObservable instance;
private ArrayList<Object> observers;
private MultiDataObservable() {
observers = new ArrayList<>();
}
public static MultiDataObservable getInstance() {
if (instance == null) {
synchronized (MultiDataObservable.class) {
if (instance == null) {
instance = new MultiDataObservable();
}
}
}
return instance;
}
@Override
public void addObserver(Object observer) {
observers.add(observer);
}
@Override
public void deleteObserver(Object observer) throws IllegalArgumentException {
if (observer == null) {
throw new IllegalArgumentException("observer must not be null");
}
if (!observers.remove(observer)) {
throw new IllegalArgumentException("observer not registered");
}
}
@Override
public <T> ArrayList<T> findObserver(Class<T> clazz) {
ArrayList<T> lists = new ArrayList<>();
for (Object observer : observers) {
if (clazz.isInstance(observer)) {
lists.add(clazz.cast(observer));
}
}
return lists;
}
}
这个类主要是有三个方法,增删找,特别是 findObserver 方法,它通过传入的 Class 对象从观察者 list 中找到符合要求的 Observer 并且返回,需要特别留意的一点是需要使用的方法是 Class.isInstance(Object object) 方法,而不是直接判断 object.getclass() == clazz ,因为后者的这种判断如果使用的是匿名内部类方式,他的类名会是 DataCommunicate$1 这种样式,所以这种方法是不可行的。最后在 secondmodule1 和 secondmodule2 中只要根据使用调用相应的方法即可,以secondmodule2 为例:
secondmodule2/DataCommunicate.class
public class DataCommunicate {
private static final String TAG = "DataCommunicate";
private static IDataListenerTwo listenerTwo = null;
public static void registerDataListenerTwo() {
IMultiDataObservable dataObservable = MultiDataObservable.getInstance();
listenerTwo = new IDataListenerTwo() {
@Override
public void OnDataChanged(DataBean data) {
Log.e(TAG, data.temperature + "");
}
};
dataObservable.addObserver(listenerTwo);
}
public static void notifyDataListenerOne() {
IMultiDataObservable dataObservable = MultiDataObservable.getInstance();
ArrayList<IDataListenerOne> lists = dataObservable.findObserver(IDataListenerOne.class);
DataBean bean = new DataBean();
bean.temperature = (int) (Math.random() * 40);
for (IDataListenerOne listener : lists) {
listener.OnDataChanged(bean);
}
}
public static void unRegisterDataListenerTwo() {
IMultiDataObservable dataObservable = MultiDataObservable.getInstance();
dataObservable.deleteObserver(listenerTwo);
}
}
最后也可以成功通信,这种方式的优点是完全可以自定义 Observer 这个接口,接口中的方法可以任意定义,具有很大的自由性,便于统一管理所有的观察者,非常方便。
事件总线大家想必已经看见过很多了,它也是一个典型的观察者模式用例,列举一下我常见的3个框架:
它们原理也不复杂, 对比之类的网上资料很多,比如Otto 框架的效率大多数时候会比不上 EventBus 等,感兴趣想要具体了解的自己动动手收集一下,我这里以使用最广泛的 greenrobot/EventBus 为例,来实现 secondmodule1 和 secondmodule2 之间的通信:public class EventNotifier {
private static volatile EventNotifier instance;
private EventNotifier() {
}
public static EventNotifier getInstance() {
if (instance == null) {
synchronized (EventNotifier.class) {
if (instance == null) {
instance = new EventNotifier();
}
}
}
return instance;
}
public void sendEvent() {
DataBean bean = new DataBean();
bean.temperature = (int) (Math.random() * 40);
EventBus.getDefault().post(bean);
}
}
secondmodule2/EventObserver.class
public class EventObserver {
private static final String TAG = "EventObserver";
private static volatile EventObserver instance;
private EventObserver() {
}
public static EventObserver getInstance() {
if (instance == null) {
synchronized (EventObserver.class) {
if (instance == null) {
instance = new EventObserver();
}
}
}
return instance;
}
public void registerObserver() {
EventBus.getDefault().register(this);
}
public void unRegisterObserver() {
EventBus.getDefault().unregister(this);
}
@Subscribe
public void onEventMainThread(DataBean bean) {
Log.e(TAG, bean.temperature + "");
}
}
特别需要注意的是,onEventMainThread 函数需要加上 @Subscribe 注解,要不然是无法工作。最后在 MainActivity 中调用相关函数即可:
@Override
protected void onCreate(Bundle savedInstanceState) {
...
EventObserver.getInstance().registerObserver();
}
@Override
protected void onDestroy() {
...
EventObserver.getInstance().unRegisterObserver();
}
@Override
public void onClick(View v) {
...
else if (v.getId() == R.id.btn_data_change_3) {
EventNotifier.getInstance().sendEvent();
}
}
最后当然也是能够成功!
观察者模式在实际开发过程中使用的场景真的挺多,比如 Activity 中两个 fragment 之间的通信,上面描述的两个同级 module 之间的通信,上层 module 与下层 module 的通信,两个 Activity 之间维护一个数据源需要做到数据实时同步等等场景,使用观察者模式之后思路简单清晰,可维护性好,而且最重要当然是耦合性低利于扩展,Android 官方源码中的 Listview 和 Adapter 也是使用了观察者模式的典型例子。
观察者模式的优点和缺点总结一下,优点:
https://github.com/zhaozepeng/Design-Patterns/tree/master/ObserverPattern
http://www.cnblogs.com/zemliu/p/3313782.html
http://blog.csdn.net/luoxianfeng89/article/details/50395901
http://blog.csdn.net/jason0539/article/details/45055233
http://ju.outofmemory.cn/entry/226121
http://www.cnblogs.com/yydcdut/p/4651208.html
http://blog.csdn.net/harvic880925/article/details/40787203
http://bianchengzhe.com/DesignPattern/neirong/221.html
java/android 设计模式学习笔记(2)---观察者模式
标签:
原文地址:http://blog.csdn.net/self_study/article/details/51346849