观察者模式:
什么是观察者模式(Observer Pattern)?这里我们举个栗子:一队警察部署在不同的位置观察着犯罪分子的活动,当犯罪分子进行某个特定的行为时,比如进行非法交易的时候,这队在不同位置的警察同时出击抓捕罪犯。这就是一种观察者模式的诠释。
观察者模式定义了一种一对多的依赖关系,当被观察者的状态发生改变时,所有依赖于它的观察者对象都会得到通知并作出自己的改变。这是一种行为型模式。
观察者主要有三大要素:被观察对象、观察者、他们之间的依赖方法。
观察者模式的优点:
- 观察者和被观察者是抽象耦合的
- 建立了一套触发机制。
Android中的使用:
我个人觉得观察者模式可能android中应用最为广泛的一种设计模式了。别的不说,就按钮的点击事件onClick而言,就可以看做为一种观察者模式,这个过程中Button其实可以被看做是被观察者,onClick事件可以看做是观察者,而setOnClickListener方法就是它们之间的添加依赖关系的方法。当Button状态发生改变时,即被点击后,则通知了onClick完成更新。
另外大家所熟知的Rxjava其核心思想也是一种观察者模式,最为直观地就是其五大基类之一的Observable,Observable通过subscribe方法去订阅Observer来完成。通过命名我们也能知道,Observable是被观察者,Observer是观察者,而subscribe方法则是它们之间的依赖方法。(需要注意的是Rxjava中的观察者模式观察者与被观察者的依赖关系是反着的,一般情况下应该是观察者去subscribe被观察者,这里则是被观察者去订阅观察者)。
接下来我们以一个简单的例子来说明观察者模式的简单代码实现,这个例子就是开头所提到的警察抓捕小偷的过程。第一步:我们需要创建一个Observer的抽象类,用来抽象观察者方法。
//被观察者的抽象方法
public abstract class Observer {
//当被观察者状态改变时,所有观察者更新方法
public abstract void update(boolean b);
}
第二步:创建被观察者对象,即是例子里的犯罪分子,并且定义一个集合observers用来存放所有的观察者对象,定义一个布尔型的isCrime来保存被观察者的状态,即犯罪分子是否实施犯罪。
/**
* 被观察者对象 -- 犯罪分子
*/
public class Offender {
//定义集合 存放所有观察者对象
private List<Observer> observers = new ArrayList<>();
private boolean isCrime;
public boolean isCrime() {
return isCrime;
}
public void setCrime(boolean crime) {
isCrime = crime;
notifyAllObservers();
}
//订阅方法 -- 添加与观察者的依赖关系
public void subscribe(Observer observer){
observers.add(observer);
}
//通知所有观察者更新
public void notifyAllObservers(){
for (Observer observer:observers) {
observer.update(isCrime());
}
}
}
第三步:创建多个继承自Observer的观察者类并实现其update方法。
//观察者 -- A警察
public class PuliceA extends Observer {
@Override
public void update(boolean b) {
if (b){
Log.i("ledding", "PuliceA 开始抓捕");
}else{
Log.i("ledding", "PuliceA 继续观察");
}
}
}
//观察者 -- B警察
public class PuliceB extends Observer {
@Override
public void update(boolean b) {
if (b){
Log.i("ledding", "PuliceB 开始抓捕");
}else{
Log.i("ledding", "PuliceB 继续观察");
}
}
}
第四步:代码中实现使用。
//创建被观察者-犯罪分子
Offender offender = new Offender();
//添加依赖关系
offender.subscribe(new PuliceA());
offender.subscribe(new PuliceB());
//还没有实施犯罪
offender.setCrime(false);
//实施犯罪
offender.setCrime(true);
最后来看下打印的日志是否实现了我们的预期。