Java设计模式 - 观察者模式

定义

  观察者模式属于对象行为型模式。

  在对象之间定义一对多的依赖,这样一来当一个对象改变状态,依赖它的对象都会收到通知并自动更新。

优点

  1、  主题和观察者之间抽象耦合。无论什么对象主要实现了特定的接口(如本文中的Observable),就可以成为观察者对象。

  2、  支持广播通信。就像一个播音员不需要知道谁在收听她的播音,只负责播音,而听不听就是听众的事了。这相当于给了你在任何时候都可以增加或者删除观察者的自由。

 

适用范围

  当对象之间是一种一对多的关系时。好比有一份文件要同时分发给多个人。

模式结构

各个角色的作用:

  Subject(主题):目标知道它的观察者。可以有任意多个观察者观察同一个目标;提供注册和删除观察者对象的接口。

  Observer(观察者):为那些在目标发生改变时需获得通知的对象定义一个更新接口。

  ConcreteSubject(具体的主题):当它的状态发生改变时,向它的各个观察者发出通知。

  ConcreteObserver(具体观察者):实现Oberserver的更新接口以使自身状态与目标状态一致。

UML图

    Java设计模式 - 观察者模式_第1张图片

两种方式:

  1、(推)主题对象主动推送;

  2、(拉)主题对象通知观察者,观察者自己去获取需要的信息;

  这两种方式会在下面介绍。

 

例子

  写一个简单的程序来说明问题:假如现在有一个广播站在播音,有许多收音机在收听。

 

  面向接口编程能够利用多态,从而降低对象之间的耦合度。

 1 package com.tony.observer;  2 
 3 /**
 4  * 具体的主题类必须实现这个接口  5  *  6  */
 7 public interface Subject {  8     
 9     //注册观察者
10     public void register(Observable observer); 11     //移除观察者
12     public void remove(Observable observer); 13     //推送消息
14     public void update(String message); 15     
16 }

 

 1 package com.tony.observer;  2 
 3 import java.util.ArrayList;  4 import java.util.List;  5 
 6 /**
 7  * 相当于ConcreteSubject,具体的主题类  8  *  9  */
10 public class Radiostation implements Subject{ 11     
12     private List<Observable> observers; 13     
14     public Radiostation(){ 15         observers = new ArrayList<Observable>(); 16  } 17     
18     public void register(Observable observer){ 19  observers.add(observer); 20         System.out.println("have "+observers.size()+" observer are listening..."); 21  } 22     
23     public void remove(Observable observer){ 24  observers.remove(observer); 25         System.out.println("a observer has gone...left "+observers.size()+" observer"); 26  } 27     
28     public void update(String message){ 29         for(Observable observer:observers){ 30  observer.update(message); 31  } 32  } 33 }

 

 1 package com.tony.observer;  2 
 3 /**
 4  * 相当于Observer,所有的观察者必须实现这个接口  5  *  6  */
 7 
 8 public interface Observable {  9     
10     //更新数据
11     public void update(String message); 12     //成为主题对象的观察者,开始监听
13     public void register(); 14     //不再监听主题对象
15     public void remove(); 16     
17     
18 }

 

 1 package com.tony.observer;  2 
 3 /**
 4  * 相当于ConcreteObserver,观察者对象  5  *  6  */
 7 public class Radio implements Observable {  8 
 9     private Subject subject; 10     
11     public Radio(Subject subject){ 12         this.subject = subject; 13  } 14 
15  @Override 16     public void update(String message) { 17  display(message); 18  } 19 
20  @Override 21     public void register() { 22         subject.register(this); 23  } 24 
25  @Override 26     public void remove() { 27         subject.remove(this); 28  } 29     
30     public void display(String message){ 31         System.out.println("get message from radiostation:"+message); 32  } 33 
34 
35 }

 

 1 package com.tony.observer;  2 /**
 3  * 测试观察者模式  4  *  5  */
 6 public class Test {  7     public static void main(String[] args) {  8         
 9         Subject radiostation = new Radiostation(); 10         
11         Radio o1 = new Radio(radiostation); 12         Radio o2 = new Radio(radiostation); 13         
14         //注册
15  o1.register(); 16  o2.register(); 17         
18         //更新消息
19         radiostation.update("hello world"); 20         radiostation.update("over"); 21         
22         //退出监听
23  o1.remove(); 24  o2.remove(); 25  } 26 }

运行结果:

Java设计模式 - 观察者模式_第2张图片

 

  这种实现方法属于“推”:主题主动将数据推送给观察者。其实还有另外一种叫做“拉”的方式:主题不主动将数据推送给观察者,只是给它们一个更新提示,接收的权利在观察者手上!

  与“拉”相比较,“推”有个很大的缺点:当推送的数据量很大的时候,会对程序运行性能产生影响!就像安卓手机某些后台应用:不经过你的同意自动将服务器中的一些数据下载的你的手机上。而“拉”这种方式就没有这样的情况,就好像你关注的公众号一样:给你推送消息时并没有把所有内容都推送过来,只是把一个标题发给你,想不想看在于你。

  但是”推“这种方式比较符合设计模式的原则,所以一般使用的都是这种方式。

 

总结

  观察者模式应用很广,不仅在你写代码的时候用到,你在生活当中也时常能够遇到:比如走在校园里收听到的广播:广播站是主题,你就是观察者。当你进入到能够听见广播的范围时,你就成了一个观察者:播音主持说的话就是要更新的数据,通过广播站这个主题将数据发送给你们,你们负责收听。

  必须能够熟练使用。

 

  其他模式:设计模式专栏

 

参考文献

  《Head First 设计模式》

  《设计模式》

 

你可能感兴趣的:(Java设计模式 - 观察者模式)