OBSERVER(观察者)—对象行为型模式

1. 意图

    定义对象间的一种一对多的依赖关系 ,当一个对象的状态发生改变时 , 所有依赖于它的对象都得到通知并被自动更新。

2. 别名

    依赖(Dependents), 发布-订阅( P u b l i s h - S u b s c r i b e )

3. 动机

    将一个系统分割成一系列相互协作的类有一个常见的副作用:需要维护相关对象间的一致性。我们不希望为了维持一致性而使各类紧密耦合,因为这样降低了它们的可重用性。


    例如, 许多图形用户界面工具箱将用户应用的界面表示与底下的应用数据分离。定义应用数据的类和负责界面表示的类可以各自独立地复用。 当然它们也可一起工作。一个表格对象和一个柱状图对象可使用不同的表示形式描述同一个应用数据对象的信息。表格对象和柱状图对象互相并不知道对方的存在,这样使你可以根据需要单独复用表格或柱状图。但在这里是它们表现的似乎互相知道。当用户改变表格中的信息时 ,柱状图能立即反映这一变化 , 反过来也是如此。

wKioL1nOJCWCQB7GAADnPIbSGx0819.png

    这种交互也称为发布-订阅(p u b l i s h - s u b s c r i b e)。目标是通知的发布者。它发出通知时并不需知道谁是它的观察者。可以有任意数目的观察者订阅并接收通知。


4. 适用性

在以下任一情况下可以使用观察者模式 :

     当一个抽象模型有两个方面 , 其中一个方面依赖于另一方面。将这二者封装在独立的对象中以使它们可以各自独立地改变和复用。

     当对一个对象的改变需要同时改变其它对象 , 而不知道具体有多少对象有待改变。

     当一个对象必须通知其它对象,而它又不能假定其它对象是谁。换言之 , 你不希望这些对象是紧密耦合的。


适用场景

    1.swing组件

    2.HTML控件事件:比如onblur,onclick

    3.JavaEE中各种监听器:ServletContextListener、HttpSessionListener、ServletRequestListener

例如:创建两个HttpSessionListener对象

public class OnlineUserListener implements HttpSessionListener {}

public class LoginUserListener implements HttpSessionListener{}

注:其实是在web.xml中创建对象


然后就会注册:类似xmlhttp.onreadystatechange=state_Change这样注册对象(这里不是调用是注册,是一个函数头指针),注册给要发事件的对象(具体的当时没写);然后事件触发之后就会回调这个函数。


    4.XMLHttpRequest

XMLHttpRequest 对象

   提供了浏览器多线程交互模式 (浏览器使用多线程和服务器交互)

    同步阻塞模式  ---  浏览器主页面使用

    异步、局部刷新模式  ---- ajax 

    回调机制 (callback,所有事件响应都是回调机制)---------- 1. 要注册   2. 等待事件触发  3. 事件发生后,通知监听者(通过回调)

a0e087f73d4ba474cd81e8a494c1894e.png


回调机制:先注册,将函数头指针传给被被注册的对象,也就是要发消息的对象。

    

5. 结构

wKioL1nOJVaBzvcEAAEFVg69b00535.png

6. 参与者

S u b j e c t(目标)

— 目标知道它的观察者。可以有任意多个观察者观察同一个目标。

— 提供注册和删除观察者对象的接口。

O b s e r v e r(观察者)

— 为那些在目标发生改变时需获得通知的对象定义一个更新接口。

C o n c r e t e S u b j e c t(具体目标)

— 将有关状态存入各C o n c r e t e O b s e r v e r对象。

— 当它的状态发生改变时, 向它的各个观察者发出通知。

C o n c r e t e O b s e r v e r(具体观察者)

— 维护一个指向C o n c r e t e S u b j e c t对象的引用。

— 存储有关状态,这些状态应与目标的状态保持一致。

— 实现O b s e r v e r的更新接口以使自身状态与目标的状态保持一致。


7.代码演示

01.目标

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public  abstract  class  Subject {
     
     //一个目标有多个观察者
     private  List<Observer> observers;
     
     //建立目标的时候再实例化对象
     public  Subject(){
         observers =  new  ArrayList<Observer>();
     }
     
     //添加观察者
     public  void  attach(Observer observer){
         observers.add(observer);
     }
     
     //移除观察者
     public   void  detach(Observer observer){
         observers.remove(observer);
     }
     
     //通知消息
     public  void  notifyMsg(String msg){
         if (observers !=  null ){
             for (Observer observer : observers ){
                 observer.receiveMsg(msg);
             }
         }
     }
}

实现接口,定义定时提醒功能

1
2
public  class  TimerService  extends  Subject{
}

02.观察者

1
2
3
4
5
6
7
8
9
10
public  abstract  class  Observer {
     
     protected  String name;
     //观察者名字
     public  Observer(String name){
         this .name = name;
     }
     //接受目标发布的消息
     public  abstract  void  receiveMsg(String msg);
}

03.写具体对象实现观察者接口

1
2
3
4
5
6
7
8
9
10
11
12
13
public  class  Teacher  extends  Observer{
 
     public  Teacher(String name) {
         super (name);
         // TODO Auto-generated constructor stub
     }
 
     @Override
     public  void  receiveMsg(String msg) {
         System.out.println( msg +  "--"  this .name +  "该讲课了" );       
     }
 
}
1
2
3
4
5
6
7
8
9
10
11
12
13
public  class  Student  extends  Observer{
 
     public  Student(String name) {
         super (name);
         // TODO Auto-generated constructor stub
     }
 
     @Override
     public  void  receiveMsg(String msg) {
         System.out.println( msg +  "--"  this .name +  "该学习了" );
     }
 
}

04.实现发布与订阅功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public  class  Test {
     
     public  static  void  main(String[] args) {
         TimerService service =  new  TimerService();
         Teacher t1 =  new  Teacher( "t1" );
         Teacher t2 =  new  Teacher( "t2" );
         Teacher t3 =  new  Teacher( "t3" );
         Student s1 =  new  Student( "s1" );
         Student s2 =  new  Student( "s2" );
         service.attach(t1);
         service.attach(t2);
         service.attach(s1);
         service.attach(t3);
         service.notifyMsg( "现在8点了" );
     }
 
}

05.结果

1
2
3
4
现在 8 点了--t1该讲课了
现在 8 点了--t2该讲课了
现在 8 点了--s1该学习了
现在 8 点了--t3该讲课了