(七),观察者模式
最后更新于:2022-04-01 09:57:10
似乎所有的设计模式都是为了使得程序具有低耦合,灵活性高,可扩展性好,程序结构清晰等等。今天的这个设计模式—观察者模式自然也不例外,但程序结构清晰可能就不是重点了。好吧,废话少说,模式这种简单粗暴的东西还是要快点学习,下面直接进入正题。
定义:观察者模式是让对象与对象之前建立一种一对多(不是Bean之前的一对多)的关系,这种关系使得当一的一方的状态改变时,所有多的一方自动根据一的一方的改变做出相应的改变。
使用场景:
1.
事件多级触发。如一个公司,CEO是最顶层的被观察者(一的一方),观察CEO的有多个经理,如:多个总经理(多的一方)同时观察CEO,而每个总经理有可以被多个其他经理观察,如:项目经理,产品经理等,那么这里的总经理即是观察者也是二级被观察者,那么只要CEO发话,相关的总经理就要做出改变,而总经理可能又要让底下的项目经理和业务经理做出改变,这就是事件多级触发;
1.
关联绑定行为,关联行为可以拆分,即解除绑定,不是“组合”,即两个行为是相互独立的,不是一个整体;
1.
跨系统消息交换场景,如消息队列,事件总线处理机制。
优点:
1.
增强程序的灵活性,可扩展性;
1.
降低程序耦合性。
缺点:
- 由于这种模式实际上是通过被观察者用一个集合存放所有的观察者的引用,然后依次遍历集合调用每个观察者的*update*方法。所以,这就产生了开发效率和运行效率的问题。还有,通常遍历是顺序的,那么所有的观察者实际上不是同时做出更新的。更有甚者,如果其中一个观察者更新出现卡顿,那么后面的观察者就要延迟做出更新了,在这种情况下,通常采用多线程异步方式,然而,带来了新的问题-并发。
下面先通过JDK自带的*Observer*类和*Observable*实现观察者模式
代码实现(利用JDK内置对象):
被观察者:
~~~
import java.util.Observable;
/**
* 被观察者
* @author lt
*
*/
public class BeObservered extends Observable{
/**
* 提交改变,调用Observable的setChanged()和notifyObservers();
* 注意:必须调用setChanged(),然后notifyObservers()才有效
*/
public void postChanged(Object news){
// 标识被被观察者有新的改变
setChanged();
// 通知所有的观察者
notifyObservers(news);
}
}
~~~
注意:
- postChanged()是我们自己写的方法;
- 必须在这个方法里面同时调用*setChanged()*和*notifyObservers()*观察者才会接受到变化,即回调*update*方法。
观察者:
~~~
import java.util.Observable;
import java.util.Observer;
/**
* 观察者
* @author lt
*
*/
public class MyObserver implements Observer{
private String name;
public MyObserver(String name){
this.name = name;
}
/**
* @param observable 该观察者观察的被观察者 即BeObservered
* @param BeObservered调用notifyObservers(Object arg)时传入的arg参数
*/
@Override
public void update(Observable observable, Object news) {
System.out.println(name+"接受到变化"+",更新的内容为:"+news);
}
@Override
public String toString() {
return "MyObserverName=" + name + "]";
}
}
~~~
这里在*update*方法里面做了点简单的反馈。
测试:
~~~
public class Test {
public static void main(String[] args) {
MyObserver observer1 = new MyObserver("小明");
MyObserver observer2 = new MyObserver("小丽");
MyObserver observer3 = new MyObserver("小强");
BeObservered beObervered = new BeObservered();
// 添加到观察者队列
beObervered.addObserver(observer1);
beObervered.addObserver(observer2);
beObervered.addObserver(observer3);
// 提交改变
beObervered.postChanged("2016,新年快乐!");
}
}
~~~
今天是新年2016的第一天,祝福大家新年快乐,心想事成,万事如意!
结果:
![这里写图片描述](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-17_56ea5b375b1cc.jpg "")
结果不用说,大家都给点反馈了(哈哈,文章点个赞,评论一番也是挺爽的)。
上面使用了JDK内置对象来实现观察者模式,其实我们也可以自己来实现观察者模式。下面我们自己来实现观察者模式吧。
自定义实现观察者模式:
被观察者:
~~~
import java.util.HashSet;
import java.util.Set;
/**
*自定义被观察者
* @author lt
*
*/
public class Observable {
public Set<Observer> observers = new HashSet<Observer>();
public boolean isChanged; // 默认为false
public void addObserver(Observer o){
// 防止多线程
synchronized (observers) {
observers.add(o);
}
}
public void setChanged(){
this.isChanged = true;
}
public void notifyObservers(Object arg){
if(isChanged){
// 遍历集合,依次通知所有的观察者
for(Observer observer : observers){
observer.update(this, arg);
}
isChanged = false; // 重置
}
}
public void notifyObservers(){
notifyObservers(null);
}
}
~~~
观察者:
~~~
public interface Observer {
public void update(Observable observable, Object news);
}
~~~
OK,自定义实现观察者模式完成了,将上面的MyObserver和BeObservered导入的JDK的Observer及Observable改成我们自己写的,运行Test测试。
结果:
和用JDK的Observer及Observable是一样的,再次祝大家新年快乐,心想事成,万事如意!。
OK,到这里我们自己定义实现观察者模式就完成了,是不是感觉好简单,就是一个回调。其实,这里也并不简单,里面肯定涉及到好多东西,什么优化啊,安全啊什么的。我们上面自己写的类就做了一个同步处理,其他的都没做,大家也可以去看看JDK源码,看看它是怎么做的。
总结:
观察者模式主要的作用是用于对象解耦,基于抽象接口(易扩展)Observer和Observable,将观察者和被观察者完全分离(低耦合),实现当被观察者发生改变时相应的所有的观察者选择做出改变。这点有很多的用途,如我们Android开发一个软件下载市场等需要不同的Activity可以同时需要看到同一个软件下载的进度,还有ListView中也用到了这种模式等等。同时,知道了这种模式的原理后,我们自己也可以定义我们的观察者和被观察者。