1 基础知识

定义:定义了对象之间的一对多依赖,让多个观察者对象同时监听某一个主题对象,当主题对象发生变化时,它的所有依赖(观察者)都会收到通知并更新。

本质:触发联动

使用场景:关联行为场景,建立一套触发机制。

(1)当一个抽象模型有两个方面,其中一个方面的操作依赖于另一个方面的状态变化那么就可以选用观察者模式,将这两者封装成观察者和目标对象,当目标对象变化的时候,依赖于它的观察者对象也会发生相应的变化。这样就把抽象模型的这两个方面分离开了,使得它们可以独立地改变和复用。

(2)如果在更改一个对象的时候,需要同时连带改变其他的对象,而且不知道究竟应该有多少对象需要被连带改变,这种情况可以选用观察者模式,被更改的那一个对象很明显就相当于是目标对象,而需要连带修改的多个其他对象,就作为多个观察者对象了

(3)当一个对象必须通知其他的对象,但是你又希望这个对象和其他被它通知的对象是松散耦合的。也就是说这个对象其实不想知道具体被通知的对象。这种情况可以选用观察者模式,这个对象就相当于是目标对象,而被它通知的对象就是观察

者对象了

优点:观察者和被观察者之间建立一个抽象的耦合;支持广播通信。缺点:观察者之间有过多的细节依赖、提高时间消耗及程序复杂度;要避免循环调用。

2 代码示例

使用场景: 观察者查看一个生成数值的对象,并将其结果显示。不过,不同的观察者显示的方式也不同。

Observer接口:

public interface Observer {
public void update(NumberGenerator numberGenerate);
}

生成数值的抽象类:NumberGenerator

public abstract class NumberGenerator {
//保存观察者们
private ArrayList observers = new ArrayList();
//添加观察者
public void addObserver(Observer observer){
observers.add(observer);
}
//删除观察者
public void deleteObserver(Observer observer){
observers.remove(observer);
}
//向observer发送通知
public void notifyObservers(){
Iterator it = observers.iterator();
while (it.hasNext()){
//调用每个观察者的update方法
Observer o = (Observer)it.next();
o.update(this);
}
}
//获取数值
public abstract int getNumber();
//生成数值
public abstract void execute();
}

子类,生成随机数:RandomNumberGenerator

public class RandomNumberGenerator extends NumberGenerator{

    //随机数生成器
private Random random = new Random();
//当前数值
private int number; //产生10个10以内的数字并向观察者发送通知
public void execute(){
for (int i = 0; i < 10; i++) {
number = random.nextInt(10);
//把每次生成的结果通知给观察者
notifyObservers();
}
} //获取当前数值
public int getNumber() {
return number;
}
}

观察者1:DigitObserver  以数字的形式显示观察得到的数值

public class DigitObserver implements Observer{

    public void update(NumberGenerator numberGenerate) {
System.out.println("观察到的数值:"+numberGenerate.getNumber());
}
}

观察者2:GraphObserver  将观察到的数值以***的形式显示出来

public class GraphObserver implements Observer{
public void update(NumberGenerator numberGenerate) {
System.out.println("图像");
int count = numberGenerate.getNumber();
for (int i = 0; i < count; i++) {
System.out.print("*");
}
System.out.println();
}
}

应用层:

public class Test {
public static void main(String[] args) {
NumberGenerator generator = new RandomNumberGenerator();
Observer observer1 = new DigitObserver();
Observer observer2 = new GraphObserver();
//添加观察者
generator.addObserver(observer1);
generator.addObserver(observer2);
generator.execute();
}
}

 注:其实Java已经为我们提供了 Observer模式了但是java.util. observer接口和java.util. Observable类并不好用。理由很简单,传递给java.util. Observer接口的 Subject y角色必须是java.util. observable类强(或者它的子类型)的。但Java只能单一继承,也就说如果 Subject 角色已经是某个类的子类了,那么它将无法继承java.util. Observable类。

3 源代码中的使用

4 相关模式

(1)观察者模式和状态模式

观察者模式和状态模式是有相似之处的。观察者模式是当目标状态发生改变时,触发并通知观察者,让观察者去执行相应的操作。而状态模式是根据不同的状态,选择不同的实现,这个实现类的主要功能就是针对状态相应地操作,它不像观察者,观察者本身还有很多其他的功能,接收通知并执行相应处理只是观察者的部分功能。当然观察者模式和状态模式是可以结合使用的。观察者模式的重心在触发联动,但是到底决定哪些观察者会被联动,这时就可以采用状态模式来实现了,也可以采用策略模式来进行选择需要联动的观察者。

(2)观察者模式和中介者模式

观察者模式和中介者模式是可以结合使用的。前面的例子中目标都只是简单地通知一下,然后让各个观察者自己去完成更新就结束了。如果观察者和被观察的目标之间的交互关系很复杂,比如,有一个界面,里面有三个下拉列表组件,分别是选择国家、省份州、具体的城市,很明显这是一个三级联动,当你选择一个国家的时候,省份/州应该相应改变数据,省份/州一改变,具体的城市也需要改变。这种情况下,很明显需要相关的状态都联动准备好了,然后再一次性地通知观察者。也就是界面做更新处理,不会仅国家改变一下,省份和城市还没有改就通知界面更新。这种情况就可以使用中介者模式来封装观察者和目标的关系在使用 Swing的小型应用里面,也可以使用中介者模式,比如,把一个界面所有的事件用一个对象来处理,把一个组件触发事件以后,需要操作其他组件的动作都封装到一起,这个对象就是典型的中介者。

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0

最新文章

  1. 设置 textarea 默认滑动到底部
  2. [Angular2 Router] Load Data Based on Angular 2 Route Params
  3. [iOS基础控件 - 4.1] APP列表
  4. $(window).width() is not a function
  5. c++中vector与list的区别
  6. Flexslider图片轮播、文字图片相结合滑动切换效果
  7. AlloyTouch.js 源码 学习笔记及原理说明
  8. IDEA中MAVEN项目打JAR包的简单方法
  9. ajaxFileUpload上传带参数,返回值改成json格式
  10. 编写高质量代码:改善Java程序的151个建议 --[26~36]
  11. 【bzoj 3252】攻略
  12. shell常用
  13. 手动挡C1驾驶学车@长建驾校
  14. IE9 下面, XMLHttpRequest 是不支持跨域请求的解决方法
  15. 从wiresharp看tcp三次握手
  16. 刷题向》一道简单的思路题BZOJ1800(EASY+)
  17. 什么是Frozen Binary
  18. hdu 1054 Strategic Game(tree dp)
  19. log4j教程 12、日志记录到数据库
  20. 在每天黄金时刻将数据库中数据获取包装成Excel表

热门文章

  1. 【转载】MyBatis批量插入数据(insert)
  2. 剑指offer1: 组类型——二维数组中的查找(给定一个数字,查找是否在该数组中)
  3. Thinkphp命令行快速生成模型类方法
  4. OkHttp3 + retrofit2 封装
  5. 作业12:List集合类
  6. Docker 启动 Mongo
  7. vue阻止右键默认行为
  8. Oracle设置权限和还原数据库
  9. JS — 事件的相关概念和DOM
  10. git冲突Pull is not possible because you have unmerged files