设计模式初探-观察者模式

观察者模式(OBSERVER),又称发布-订阅(Publish-Subscribe),依赖(Dependents),通过定义对象间的一对多的依赖关系,达到当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动更新,属于对象行为型模式。观察者模式在软件设计中很常用,比如经典的MVC模式,Model为目标类,View为观察者,Controller为更新管理器。首先更新管理器即控制器先将视图和模型建立关联关系,然后当模型数据改变时,这些改变会自动反映在视图上,从而达到了业务和显示分离的效果。Java默认支持观察者模式,AWT1.1之后版本,Servlet,SAX2的事件处理模型均为基于观察者模式的委托事件模型(Delegation Event Model或DEM)。在DEM模型里面,主题(Subject)角色负责发布(publish)事件,而观察者角色向特定的主题订阅(subscribe)它所感兴趣的事件。当一个具体主题产生一个事件时,它就会通知所有感兴趣的订阅者。观察者模式提供了一种将发布者与订阅者松散地耦合在一起的联系形式,以及一种能够动态地登记、取消向一个发布者的订阅请求的办法。

一、使用场景

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

2、当对一个对象的改变需要同时改变其他对象,而又不知道具体有多少对象及这些对象是谁。

3、建立链式触发机制,A影响B,B影响C,C影响D等等。

二、UML图

观察者模式uml

三、Java实现

[java]  view plain  copy
  1. package study.patterns.observer;  
  2.   
  3. import java.text.SimpleDateFormat;  
  4. import java.util.ArrayList;  
  5. import java.util.Date;  
  6. import java.util.List;  
  7. /** 
  8.  * 观察者模式 
  9.  * @author qbg 
  10.  */  
  11. public class ObserverPattern {  
  12.     public static void main(String[] args) {  
  13.         ClockTimerSubject timer = new ClockTimerSubject();//目标  
  14.         DigitalClock digital = new DigitalClock(timer);//观察者  
  15.         BigBenClock bigben = new BigBenClock(timer);//观察者  
  16.         TimerTask task = new TimerTask(timer);//定时任务  
  17.         task.start();//启动定时任务  
  18.     }  
  19. }  
  20. /** 
  21.  * 抽象目标类  
  22.  */  
  23. abstract class Subject{  
  24.     protected List<Observer> observers = new ArrayList<Observer>();  
  25.       
  26.     /** 
  27.      *  注册观察者 
  28.      */  
  29.     public void attach(Observer obs){  
  30.         observers.add(obs);  
  31.     }  
  32.       
  33.     /** 
  34.      * 删除观察者 
  35.      */  
  36.     public void detach(Observer obs){  
  37.         observers.remove(obs);  
  38.     }  
  39.       
  40.     /** 
  41.      * 通知观察者的抽象方法 
  42.      */  
  43.     public abstract void notifyObs();  
  44. }  
  45. /** 
  46.  * 具体目标类,每秒更新下自己的内部时间状态  
  47.  */  
  48. class ClockTimerSubject extends Subject{  
  49.     private String time;  
  50.       
  51.     /** 
  52.      * 具体通知方式,通知所有观察者 
  53.      */  
  54.     @Override  
  55.     public void notifyObs() {  
  56.         for(Observer obs : this.observers){  
  57.             obs.update(this);  
  58.         }  
  59.     }  
  60.   
  61.     /** 
  62.      * 更新time,并将改变通知给观察者 
  63.      */  
  64.     public void tick(){  
  65.         SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  
  66.         time = sdf.format(new Date());  
  67.         notifyObs();  
  68.     }  
  69.       
  70.     public String getTime() {  
  71.         return time;  
  72.     }  
  73.   
  74.     public void setTime(String time) {  
  75.         this.time = time;  
  76.     }  
  77. }  
  78. /** 
  79.  * 观察者抽象接口,只有一个update方法  
  80.  */  
  81. interface Observer{  
  82.     public void update(ClockTimerSubject subject);  
  83. }  
  84. /** 
  85.  * 钟表绘制接口 
  86.  */  
  87. interface Widget{  
  88.     public void draw();  
  89. }  
  90. /** 
  91.  * 数字钟表,具体观察者 
  92.  */  
  93. class DigitalClock implements Widget,Observer{  
  94.     private ClockTimerSubject subject;  
  95.       
  96.     /** 
  97.      * 初始化目标,并将自己注册到该目标的观察者列表中  
  98.      */  
  99.     public DigitalClock(ClockTimerSubject subject){  
  100.         this.subject = subject;  
  101.         this.subject.attach(this);  
  102.     }  
  103.       
  104.     /** 
  105.      * 先检查发出通知的目标是否为自己注册过的,是则响应  
  106.      */  
  107.     @Override  
  108.     public void update(ClockTimerSubject subject) {  
  109.         if(this.subject == subject){  
  110.             draw();  
  111.         }  
  112.     }  
  113.   
  114.     @Override  
  115.     public void draw() {  
  116.         System.out.println("电子闹钟为您报时:"+subject.getTime());  
  117.     }  
  118. }  
  119. /** 
  120.  * 大笨钟,具体观察者 
  121.  */  
  122. class BigBenClock implements Widget,Observer{  
  123. private ClockTimerSubject subject;  
  124.       
  125.     /** 
  126.      * 初始化目标,并将自己注册到该目标的观察者列表中  
  127.      */  
  128.     public BigBenClock(ClockTimerSubject subject){  
  129.         this.subject = subject;  
  130.         this.subject.attach(this);  
  131.     }  
  132.       
  133.     /** 
  134.      * 先检查发出通知的目标是否为自己注册过的,是则响应  
  135.      */  
  136.     @Override  
  137.     public void update(ClockTimerSubject subject) {  
  138.         if(this.subject == subject){  
  139.             draw();  
  140.         }  
  141.     }  
  142.   
  143.     @Override  
  144.     public void draw() {  
  145.         System.out.println("伦敦大笨钟为您报时:"+subject.getTime());  
  146.     }  
  147. }  
  148. /** 
  149.  * 定时任务,每秒更新一次ClockTimerSubject的状态 
  150.  */  
  151. class TimerTask extends Thread{  
  152.     private ClockTimerSubject timer;  
  153.       
  154.     public TimerTask(ClockTimerSubject timer){  
  155.         this.timer = timer;  
  156.     }  
  157.   
  158.     @Override  
  159.     public void run() {  
  160.         while(true){  
  161.             try {  
  162.                 timer.tick();  
  163.                 Thread.sleep(1000);  
  164.             } catch (InterruptedException e) {  
  165.                 e.printStackTrace();  
  166.             }  
  167.         }  
  168.     }  
  169. }  
运行结果:

[plain]  view plain  copy
  1. 电子闹钟为您报时:2014-02-12 21:44:48  
  2. 伦敦大笨钟为您报时:2014-02-12 21:44:48  
  3. 电子闹钟为您报时:2014-02-12 21:44:49  
  4. 伦敦大笨钟为您报时:2014-02-12 21:44:49  
  5. 电子闹钟为您报时:2014-02-12 21:44:50  
  6. 伦敦大笨钟为您报时:2014-02-12 21:44:50  
  7. 电子闹钟为您报时:2014-02-12 21:44:51  
  8. 伦敦大笨钟为您报时:2014-02-12 21:44:51  
四、模式优缺点

优点:

1、目标和观察者间的抽象耦合。目标仅知道它有一系列符合抽象接口Observer的观察者,而不知道这些观察者属于哪个具体的类,这样目标和观察者之间的耦合就是抽象的和最小的。

2、支持广播通信。观察目标会向所有已注册的观察者对象发送通知,具体如何处理通知由观察者决定,简化了一对多系统的设计难度。

缺点:

1、意外的更新。由于观察者仅仅知道目标改变了,而不晓得具体什么被改变了,目标上的一个看似无害的操作可能会引起一系列对观察者及依赖于这些观察者的对象的更新,导致错误的产生。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值