Java设计模式----观察者模式详解

【正文】

一、观察者模式的定义:

简单地说,观察者模式定义了一个一对多的依赖关系,让一个或多个观察者对象监听一个主题对象。这样一来,当被观察者状态发生改变时,需要通知相应的观察者,使这些观察者对象能够自动更新。例如:GUI中的事件处理机制采用的就是观察者模式。

 

二、观察者模式的实现:

  • Subject(被观察的对象接口):规定ConcreteSubject的统一接口 ; 每个Subject可以有多个Observer;
  • ConcreteSubject(具体被观察对象):维护对所有具体观察者的引用的列表 ;–状态发生变化时会发送通知给所有注册的观察者。
  • Observer(观察者接口):规定ConcreteObserver的统一接口;定义了一个update()方法,在被观察对象状态改变时会被调用。
  • ConcreteObserver(具体观察者):维护一个对ConcreteSubject的引用;特定状态与ConcreteSubject同步; 实现Observer接口,update()方法的作用:一旦检测到Subject有变动,就更新信息。

图表描述如下:

注:在被观察者类中需要有一个集合维护所有观察者。

 

三、举例说明:

【方案一】:自己定义接口或者类来实现观察者模式。

步骤如下:

(1)定义被观察者所具有的接口:

 1 package com.vince.observer;
 2 public interface Observable {
 3     //注册为一个观察者
 4     public void registerObserver(Observer observer);
 5
 6     //取消观察者
 7     public void removeObserver(Observer observer);
 8
 9     //通知所有观察者更新信息
10     public void notifyObservers();
11 }

(2)定义具体的被观察者:杯子

 1 package com.vince.observer;
 2 import java.util.Vector;
 3
 4 public class Cup implements Observable{
 5     //被观察者维护的一个观察者对象列表
 6     private Vector<Observer> vector = new Vector<Observer>();
 7     private float price;
 8
 9     public Cup(float price){
10         this.price = price;
11     }
12
13     public float getPrice() {
14         return price;
15     }
16     public void setPrice(float price) {
17         //修改价格时,通知所有观察者
18         this.price = price;
19         notifyObservers();
20     }
21     @Override
22     public void registerObserver(Observer observer) {
23         //注册观察者
24         vector.add(observer);
25     }
26     @Override
27     public void removeObserver(Observer observer) {
28         //取消观察者
29         vector.remove(observer);
30     }
31     @Override
32     public void notifyObservers() {
33         //实现通知所有的观察者对象
34         for (Observer observer:vector) {
35             observer.update(price);
36         }
37     }
38 }

(3)定义观察者所具有的共同的接口:(更新数据最终当然是在观察者那里进行啦)

1 package com.vince.observer;
2
3 public interface Observer {
4     public void update(float price);
5 }

(4)定义具体的观察者对象:

 1 package com.vince.observer;
 2 public class Person implements Observer{
 3     private String name;
 4     public Person(String name){
 5         this.name = name;
 6     }
 7     @Override
 8     public void update(float price) {
 9         System.out.println(name+"关注的杯子的价格已更新为:"+price);
10     }
11 }

(5)测试:

 1 package com.vince.observer;
 2 public class Test {
 3     public static void main(String[] args) {
 4         //创建一个被观察者对象
 5         Cup doll  = new Cup(3000);
 6         //创建两个观察者对象
 7         Person p1 = new Person("生命壹号");
 8         Person p2 = new Person("生命贰号");
 9         //注册成为一个观察者
10         doll.registerObserver(p1);
11         doll.registerObserver(p2);
12
13         System.out.println("第一轮促销:");
14         doll.setPrice(2698);// 价格变动
15         System.out.println("第二轮促销:");
16         doll.setPrice(2299);//
17         System.out.println("第三轮促销:");
18         doll.setPrice(1998);
19
20         doll.removeObserver(p2);    //将生命二号移除
21         System.out.println("第四轮促销:");
22         doll.setPrice(1098);
23
24     }
25 }

运行后,显示结果如下:

 

 

【方案二】:直接调用JDK的API去实现。

步骤如下:

(1) 通过继承Observable类实现具体的被观察者对象:

 1 package com.vince.observer2;
 2 import java.util.Observable;
 3
 4 public class Cup extends Observable{
 5     private float price;
 6
 7     public Cup(float price){
 8         this.price = price;
 9     }
10     public float getPrice() {
11         return price;
12     }
13     public void setPrice(float price) {
14         this.price = price;
15         this.setChanged();//通知,数据已改变
16         this.notifyObservers();
17     }
18
19
20 }

(2)通过实现java.util.Observer接口实现具体的观察者对象:

 1 package com.vince.observer2;
 2 import java.util.Observable;
 3 import java.util.Observer;
 4
 5 public class Person implements Observer{
 6     private String name;
 7     public Person(String name){
 8         this.name = name;
 9     }
10     @Override
11     public void update(Observable o, Object arg) {
12         if(o instanceof Cup){
13             Cup cup = (Cup)o;
14             System.out.println(name+"关注的杯子价格已更新为:"+cup.getPrice());
15         }
16     }
17 }

(3)测试:

 1 package com.vince.observer2;
 2 public class Test {
 3     public static void main(String[] args) {
 4         Cup cup = new Cup(3000);
 5         Person p1 = new Person("生命壹号");
 6         Person p2 = new Person("生命贰号");
 7         cup.addObserver(p1);
 8         cup.addObserver(p2);
 9         System.out.println("第一轮促销");
10         cup.setPrice(2988);
11         System.out.println("第二轮促销");
12         cup.setPrice(2698);
13
14         cup.deleteObserver(p2);
15         System.out.println("第三轮促销");
16         cup.setPrice(1998);
17     }
18 }

运行后,结果如下:

【工程文件】

链接:http://pan.baidu.com/s/1c03rLFM

密码:hois

 

四、总结:(观察者模式的作用)

  • 观察者模式在被观察者和观察者之间建立一个抽象的耦合。被观察者角色所知道的只是一个具体观察者列表。

        由于被观察者和观察者没有紧密地耦合在一起,因此它们可以属于不同的抽象化层次。如果被观察者和观察者都被扔到一起,那么这个对象必然跨越抽象化和具体化层次。

  • 观察者模式支持广播通讯。被观察者会向所有的登记过的观察者发出通知。
时间: 2025-01-25 08:19:33

Java设计模式----观察者模式详解的相关文章

Java 反射机制详解及实例代码_java

Java反射详解 本篇文章依旧采用小例子来说明,因为我始终觉的,案例驱动是最好的,要不然只看理论的话,看了也不懂,不过建议大家在看完文章之后,在回过头去看看理论,会有更好的理解. 下面开始正文. [案例1]通过一个对象获得完整的包名和类名 package Reflect; /** * 通过一个对象获得完整的包名和类名 * */ class Demo{ //other codes... } class hello{ public static void main(String[] args) {

Java实例化类详解_java

Java 中实例化类的动作,你是否还是一成不变 new 对应对象呢?     经手的项目多了,代码编写量自然会增加,渐渐的会对设计模式产生感觉.     怎样使书写出来的类实例化动作,高内聚,低耦合,又兼具一定的扩展能力呢?     本文试图从几段鲜活的代码入手,给大家呈现不一样的 Java 实例化类.     下面代码取自 com.google.zxing 源码实现: public BitMatrix encode(String contents, BarcodeFormat format,

Java中单例模式详解_java

单例模式概念: java中单例模式是一种常见的设计模式,单例模式分三种:懒汉式单例.饿汉式单例.登记式单例三种. 单例模式有一下特点: 1.单例类只能有一个实例. 2.单例类必须自己自己创建自己的唯一实例. 3.单例类必须给所有其他对象提供这一实例. 单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例.在计算机系统中,线程池.缓存.日志对象.对话框.打印机.显卡的驱动程序对象常被设计成单例.这些应用都或多或少具有资源管理器的功能.每台计算机可以有若干个打印机,但只能有一个Pr

Java中文问题详解,底层编码解剖

编码|问题|详解|中文 Java中文问题详解预备知识: 1.字节和unicode Java内核是unicode的,就连class文件也是,但是很多媒体,包括文件/流的保存方式 是使用字节流的. 因此Java要对这些字节流经行转化.char是unicode的,而byte是字节. Java中byte/char互转的函数在sun.io的包中间有.其中ByteToCharConverter类是中调度, 可以用来告诉你,你用的Convertor.其中两个很常用的静态函数是 public static By

Java控制台输入输出详解

初学java时,或许大家都遇到过一个问题,从控制台获取字符,大家最常见的便是通过System.in.read();取得输入的字符,代码如下: public static void receiveOneChar(){//得到一个输入的字符 char ch='2'; System.out.println("please enter a number:"); try { ch=(char)System.in.read(); } catch (IOException e) { e.printS

java RMI原理详解

[本文转载自java RMI原理详解] 定义 RMI(Remote Method Invocation)为远程方法调用,是允许运行在一个Java虚拟机的对象调用运行在另一个Java虚拟机上的对象的方法. 这两个虚拟机可以是运行在相同计算机上的不同进程中,也可以是运行在网络上的不同计算机中. Java RMI:Java远程方法调用,即Java RMI(Java Remote Method Invocation)是Java编程语言里,一种用于实现远程过程调用的应用程序编程接口.它使客户机上运行的程序

java split()函数详解

java split()函数详解 public string[] split(string regex,int limit)根据匹配给定的正则表达式来拆分此字符串. 此方法返回的数组包含此字符串的每个子字符串,这些子字符串由另一个匹配给定的表达式的子字符串终止或由字符串结束来终止.数组中的子字符串按它们在此字符串中的顺序排列.如果表达式不匹配输入的任何部分,则结果数组只具有一个元素,即此字符串 */  string[] timefirs=new string[3];  string timefi

Java反射机制详解_java

本文较为详细的分析了Java反射机制.分享给大家供大家参考,具体如下: 一.预先需要掌握的知识(java虚拟机) java虚拟机的方法区: java虚拟机有一个运行时数据区,这个数据区又被分为方法区,堆区和栈区,我们这里需要了解的主要是方法区.方法区的主要作用是存储被装载的类 的类型信息,当java虚拟机装载某个类型的时候,需要类装载器定位相应的class文件,然后将其读入到java虚拟机中,紧接着虚拟机提取class 中的类型信息,将这些信息存储到方法区中.这些信息主要包括: 1.这个类型的全

Java并发控制机制详解_java

在一般性开发中,笔者经常看到很多同学在对待java并发开发模型中只会使用一些基础的方法.比如Volatile,synchronized.像Lock和atomic这类高级并发包很多人并不经常使用.我想大部分原因都是来之于对原理的不属性导致的.在繁忙的开发工作中,又有谁会很准确的把握和使用正确的并发模型呢? 所以最近基于这个思想,本人打算把并发控制机制这部分整理成一篇文章.既是对自己掌握知识的一个回忆,也是希望这篇讲到的类容能帮助到大部分开发者.  并行程序开发不可避免地要涉及多线程.多任务的协作和