观察者模式在android中的应用来自于远程更新数据和UI。
例如:当我们setAdapter(ListAdapter adapter)时,BaseAdapter同时注册了AdapterDataSetObserver();也就是说当我们添加一个适配器的时候,这个适配器已经在内部注册了一个观察者模式。
观察者模式的特点:
1,将一个系统的功能分割成一系列相互协作的类。当一个通知者对象的状态发送改变时,所以依赖于它的观察者对象都得到通知并被自动更新。
2,一个通知者可以有无数个依赖于它的观察者。通知者发出通知的时候不需要知道他的观察者是谁。
3,任何一个具体的观察者也不需要知道其他通知者的存在。
副作用
但是也是有副作用的,观察者模式需要维护观察和通知对象间的相对一致性。
那么这就是一种强耦合,会给维护和拓展带来不便。
观察这模式使用的场景
1,当一个对象的改变需要同时改变其他对象的时候。并且在程序不知道到底目标对象有多少个的时候,就应该使用。
2,当一个逻辑中一个方面要依赖于另一个方面的时候,这个时候就应该用观察者模式将两个具体逻辑封装在独立的对象,这样可以让他们独自改变和复用。
总结
观察者模式的工作目的是为了解耦。让耦合的双方依赖于抽象,而不是依赖于具体。从而使得各自的变化不会影响到另一边。所以,观察者模式是“依赖倒转原则”的最佳体现。
好了,观察者模式的概念和理论已经说完了。接下来看代码,看看具体的实现过程。
这里我借用《大话设计模式》中的例子来说明。
/** * 通知抽象类,他可以有任何数量的观察者 * 提供接口,增加删除观察者 */
public abstract class Subject {
//同事列表,就是观察者实例集合
private List<Observer> observers = new ArrayList<>();
//增加请求秘书帮忙的同事
public void addObserver(Observer stock) {
observers.add(stock);
}
//清除请求秘书帮忙的同事
public void removeObserver(Observer stock) {
if (observers.contains(stock))
observers.remove(stock);
}
//通知
public void notice() {
for (Observer stock : observers) {
stock.update();
}
}
}
首相,定义一个通知者的抽象类。
List observers就是存放所有观察者的实例。
addObserver/removeObserver;添加/删除观察者的方法。
notice();向所有观察者发送通知的方法。
/** * 抽象观察者,为所有具体观察者提供接口 * update为更新方法 */
public abstract class Observer {
public abstract void update();//更新方法
}
再定义一个观察者抽象类
观察者抽象类很简单,就包含一个接到通知者发送的通知后调用的更新数据的方法。
**
* 具体观察者
* 具体观察者可以保存一个具体的通知者对象
*/
public class ConcreteObserver extends Observer {
@Override
public void update() {
//处理自己的逻辑
}
}
然后,实现具体观察者类
具体观察者类实现的目的就是为了接收到通知者的消息
**
* 具体通知者
* 将具体状态存入
* 内部改变是给所有观察者发出通知
*/
public class ConcreteSubject extends Subject {
private String subjectState;//发出通知需要改变的逻辑(这里是一个常量)
public String getSubjectState() {
return subjectState;
}
public void setSubjectState(String subjectState) {
this.subjectState = subjectState;
}
}
然后,实现通知者类
具体通知者类里面只包含如果状态改变,发送通知的话,应该发送的逻辑。这里,subjectState就是需要发送的逻辑。
//实现方法
private test() {
//实例化一个通知者
ConcreteSubject concreteSubject = new ConcreteSubject();
//实例化无数个需要被通知的观察者
Observer concreteObserverOne = new ConcreteObserver(concreteSubject, "a");
Observer concreteObserverTow = new ConcreteObserver(concreteSubject, "b");
Observer concreteObserverThree = new ConcreteObserver(concreteSubject, "c");
Observer concreteObserverFour = new ConcreteObserver(concreteSubject, "d");
Observer concreteObserverFive = new ConcreteObserver(concreteSubject, "e");
Observer concreteObserverSix = new ConcreteObserver(concreteSubject, "f");
//记录需要发通知的观察者
concreteSubject.addObserver(concreteObserverOne);
concreteSubject.addObserver(concreteObserverTow);
concreteSubject.addObserver(concreteObserverThree);
concreteSubject.addObserver(concreteObserverFour);
concreteSubject.addObserver(concreteObserverFive);
concreteSubject.addObserver(concreteObserverSix);
//通知者发现状态改变了
concreteSubject.setSubjectState("老板来了,不要做与工作无关的事情了");
//发通知
concreteSubject.notice();
}
结果就是,当老板来了,作为通知者的秘书(ConcreteSubject)发出通知,而提前给秘书打招呼说“老板来了说一声”的同事a~f都会得到这个通知。然后开始处理自己的逻辑。
好了,这就是观察者模式。不要小看这几个类。用起来可不简单。
现在我们来分析一下。
接下来我将把这个简单的观察者模式的例子改成一个实际可用的,以网络请求为例。不同的代码我会贴出来。
首要要建立一个通知者(Subject)的抽象。
List observers:这个Subject里面包含了一个集合,这个集合用来装所有到它这里注册的观察则会(Observer)。
addObserver/removeObserver:注册和反注册观察者的方法。
notice():给所有注册了的观察者发送通知。
//通知
public void notice(ConcreteSubject concreteSubject) {
for (Observer stock : observers) {
if (concreteSubject.getStatus() == 200) {
stock.onSuccess(concreteSubject.getStatus(), concreteSubject.getContent());
} else if (concreteSubject.getStatus() == 300) {
stock.onFinal(concreteSubject.getStatus(), concreteSubject.getErrorCode(), concreteSubject.getMessage());
}
}
}
接下来建立一个观察者的(Observer)抽象。
我们设计一个网络请求。那么就需要onSuccess(成功)和onFinal(失败)两个方法。网络请求返回这两个方法后会发送给所有可以接收网络请求结果的类。
代码如下:
public abstract class Observer {
public abstract void onSuccess(int status,Object content);//成功
public abstract void onFinal(int status,int errorCode,String message);//失败
}
好。接下来,我们建立具体通知者(ConcreteSubject);
在这里,具体的通知者完全是个实体类
public class ConcreteSubject extends Subject {
private int status;
private int errorCode;
private String message;
private Object content;
public ConcreteSubject(int status, int errorCode, String message, Object content) {
this.status = status;
this.errorCode = errorCode;
this.message = message;
this.content = content;
}
//还有它们的get/set方法
}
具体通知者其实就是保存的需要发送的通知内容的逻辑代码。
网络请求需要发送的逻辑代码,都写在ConcreteSubject里面了。
接下来是具体观察者(ConcreteObserver)
@Override
public void onSuccess(int status, Object content) {
//处理自己的逻辑
}
@Override
public void onFinal(int status, int errorCode, String message) {
//处理自己的逻辑
}
这样一改造,我们就改造了一个网络请求的工厂模式。
具体用法如下:
private test() {
//发送一个网络请求的时候,就相当于实例化一个通知者
ConcreteSubject concreteSubject = new ConcreteSubject(201, 0, null, "登陆中");
//所有需要接受网络请求回调结果的类,这里只写了一个ConcreteObserver,其实只要继承了抽象类Observer的都可以接收到通知
Observer concreteObserverOne = new ConcreteObserver();
Observer concreteObserverTow = new ConcreteObserver();
Observer concreteObserverThree = new ConcreteObserver();
Observer concreteObserverFour = new ConcreteObserver();
Observer concreteObserverFive = new ConcreteObserver();
Observer concreteObserverSix = new ConcreteObserver();
//记录需要发通知的观察者
concreteSubject.addObserver(concreteObserverOne);
concreteSubject.addObserver(concreteObserverTow);
concreteSubject.addObserver(concreteObserverThree);
concreteSubject.addObserver(concreteObserverFour);
concreteSubject.addObserver(concreteObserverFive);
concreteSubject.addObserver(concreteObserverSix);
//网络请求结果回调了过来,改变通知者的数据
concreteSubject.setStatus(200);
concreteSubject.setContent("登陆成功");
//发通知
concreteSubject.notice(concreteSubject);
//这样,所有的观察者都能够接收到网络请求成功的通知
}
其实,这个时候,抽象类(Observer)完全可以用接口代替。
这其中还有很多可以优化的地方。比如清理掉所有的观察者。这时候要考虑线程问题。集合的循环遍历,可以考虑线程池,当然不改变ui只发送数据的话,那就更加简单了。还有很多可以优化的地方。这个可以自己在实战中慢慢总结。
前面也总结了设计模式的好与坏。
希望理论总结+代码可以让每个看到这篇博文,想要学习观察者模式的程序员们有一些收获。