设计模式之--观察者模式

来源:互联网 发布:mac pro怎么安装双系统 编辑:程序博客网 时间:2024/06/16 16:10
 

设计模式之--观察者模式

        网上对设计模式的分享和笔记已经很多了,我依然在此写这一篇十分没有新意的东西,这主要是一来记录下自己最近一段时间的学习生活,另一来是希望通过这篇博文来重新启动一下自己的博客灌水生活,很久没有写东西了,看着尘封已久的博客、回首那段记忆空白的日子,有点惶恐的感觉,这么长的时间我竟连一点痕迹都没留下,我这样的存在实在是太过于环保了。好吧,废话就此打住,让我们进入主题。


1.什么是观察者模式

       按照《Head First Design Pattern》的定义,观察者模式用于定义一种对象之间的一对多的关系,使得其中的某一个对象发生变化时,其他对此感兴趣的对象能被通知,并自动更新状态。

在观察者模式中,有一个被观察主体(Subject)用于发布(Publish)状态(State),此外还有多个观察者对象(Observer Object)。观察者对象通过向被观察主体注册或者订阅(Register or Subscribe)表示自己对Subject发布的状态感兴趣。Subject对象定时(根据自身状态的改变)主动将状态信息告知Observer对象(push方式)或者通知观察者对象取其所感兴趣的信息(pull方式)。

       观察者模式中,Subject不关心Observer的实现方式,不关心Observer的加入和退出;Observer对象也不关心Subject的实现方式,只要求其实现了特定的接口,能提供其感兴趣的信息。


2. 应用场景

       观察者模式又名发布者模式,顾名思义这种模式主要运用在当一种对象需要对外发布状态时,主要运用在对象之间存在多对一的依赖关系时候,让多个观察者对象能够根据被观察主体状态的改变自动更新(update)自己。


3. 实现方式

         在观察者模式的设计实现中,由于要求彼此之间的松耦合,彼此不再关心对方的具体实现,只要求对方实现特定的接口即可。因此,要求观察者主体(Subject)具体实现类必须实现Subject接口,而观察者对象(Observer)具体实现类必须Observer接口。原谅我没有找到画类图的工具,所以我借用网上的一张图片以表示这种关系。

(观察者模式结构,引自supercrsky)

Subject接口定义了三个方法,分别是attatch(向Subject注册观察者)、detach(从注册的观察表中删除)、notifyObservers(通知观察者对象)。Observer接口定义了一个方法update,用于接收Subject的更新调用。在Subject具体类的实现中因为需要维持观察者的信息,所以需要定义一个List用于保存所有的观察者对象引用。

        下面通过一个简单的例子向大家讲一下观察者模式的具体实现,在本例子中被观察者主体在感知到自身的状态(message)发生变化之后,将消息发送给所有的观察者对象。本例中定义了三种不同的观察者实现类,他们以不同的方式展现接收到的消息,分别是原样展示、转化成大写展示,转换成小写展示。

---------------- Subject.java

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. package cn.ac.ict.chengenbao;  
  2.   
  3. public interface Subject {  
  4.     public void registerObserver(Observer obj);  
  5.     public void removeObserver(Observer obj);  
  6.     public void notifyObservers();  
  7. }  

----------------- Observer.java

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. package cn.ac.ict.chengenbao;  
  2.   
  3. public interface Observer {  
  4.     public void update(String message);  
  5. }  

--------------------- SubjectImpl.java

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. package cn.ac.ict.chengenbao;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.List;  
  5.   
  6. public class SubjectImpl implements Subject {  
  7.     private List<Observer> observerList = null;  
  8.     private String msg = null;  
  9.       
  10.     public SubjectImpl() {  
  11.         observerList = new ArrayList<Observer>();  
  12.     }  
  13.   
  14.     public void registerObserver(Observer obj) {  
  15.         // TODO Auto-generated method stub  
  16.         observerList.add(obj);  
  17.     }  
  18.   
  19.     public void removeObserver(Observer obj) {  
  20.         // TODO Auto-generated method stub  
  21.         observerList.remove(obj);  
  22.     }  
  23.   
  24.     public void notifyObservers() {  
  25.         // TODO Auto-generated method stub  
  26.         for( Observer o : observerList) {  
  27.             o.update(msg);  
  28.         }  
  29.           
  30.         if ( observerList.size() == 0 ) {  
  31.             System.out.println("There is no observers in the list.");  
  32.         }  
  33.     }  
  34.       
  35.     public void changeMessage(String message) {  
  36.         msg = message;  
  37.         this.notifyObservers();  
  38.     }  
  39.   
  40. }  

------------------------ OriginOutputer.java

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. package cn.ac.ict.chengenbao;  
  2.   
  3. public class OriginOutputer implements Observer {  
  4.     private Subject subject = null;  
  5.       
  6.     public OriginOutputer(Subject s) {  
  7.         subject = s;  
  8.         s.registerObserver(this);  
  9.     }  
  10.   
  11.     public void update(String message) {  
  12.         // TODO Auto-generated method stub  
  13.         this.display(message);  
  14.     }  
  15.       
  16.     private void display(String message) {  
  17.         System.out.println(this.getClass().getName() + ":" + message);  
  18.     }  
  19.       
  20.     public void leave() {  
  21.         this.display("I remove myself from the ObserverList...");  
  22.         subject.removeObserver(this);  
  23.     }  
  24.   
  25. }  

----------------------- UpperOutputer.java

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. package cn.ac.ict.chengenbao;  
  2.   
  3. public class UpperOutputer implements Observer {  
  4.     private Subject subject = null;  
  5.       
  6.     public UpperOutputer(Subject s) {  
  7.         subject = s;  
  8.         s.registerObserver(this);  
  9.     }  
  10.   
  11.     public void update(String message) {  
  12.         // TODO Auto-generated method stub  
  13.         this.display(message);  
  14.     }  
  15.       
  16.     private void display(String message) {  
  17.         System.out.println(this.getClass().getName() + ":" + message.toUpperCase());  
  18.     }  
  19.       
  20.     public void leave() {  
  21.         this.display("I remove myself from the ObserverList...");  
  22.         subject.removeObserver(this);  
  23.     }  
  24. }  

---------------------------- LowerOutputer.java

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. package cn.ac.ict.chengenbao;  
  2.   
  3. public class LowerOutputer implements Observer {  
  4.     private Subject subject = null;  
  5.       
  6.     public LowerOutputer(Subject s) {  
  7.         subject = s;  
  8.         s.registerObserver(this);  
  9.     }  
  10.   
  11.     public void update(String message) {  
  12.         // TODO Auto-generated method stub  
  13.         this.display(message);  
  14.     }  
  15.       
  16.     private void display(String message) {  
  17.         System.out.println(this.getClass().getName() + ":" + message.toLowerCase());  
  18.     }  
  19.       
  20.     public void leave() {  
  21.         this.display("I remove myself from the ObserverList...");  
  22.         subject.removeObserver(this);  
  23.     }  
  24.   
  25. }  

------------------------ Test.java

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. package cn.ac.ict.chengenbao;  
  2.   
  3. public class Test {  
  4.     public static void main(String[] args) {  
  5.         SubjectImpl subject = new SubjectImpl();  
  6.         LowerOutputer lowerOuter = new LowerOutputer(subject);  
  7.         UpperOutputer upperOuter = new UpperOutputer(subject);  
  8.         OriginOutputer originOuter = new OriginOutputer(subject);  
  9.           
  10.         subject.changeMessage("Message1");  
  11.         originOuter.leave();  
  12.         subject.changeMessage("Message2");  
  13.         lowerOuter.leave();  
  14.         subject.changeMessage("Message3");  
  15.         upperOuter.leave();  
  16.           
  17.         subject.changeMessage("Message4");  
  18.     }  
  19. }  

运行结果:


4. JDK API 对观察者模式的支持

         JDK API 中提供了对观察者模式的原生支持。在 java.util 包中,包含Observer接口和Observable类,开发者可以通过实现Observer接口和继承Observable类来实现观察者模式。

        使用JAVA自带的观察者模式会受到以下限制:

         1) java.util.Observable是个类而不是接口,这使得要实现的Subject类不能继承其他的类,从而使得一些原有的类不能迁移至观察者模式。同时,通过继承实现Subject模式也违背了我们“Program to the interface”的一贯原则。

         2)Observable实现中对一些关键的方法进行了访问保护,比如说setChanged方法,只有继承自Observable的类才能调用该方法。


原文:http://blog.csdn.net/chengenbao/article/details/17585881

0 0
原创粉丝点击