设计模式:观察者(Observer)模式

一、前言

  观察者模式其实最好的名称应该是“发布订阅”模式,和我们现在大数据之中的发布订阅方式比较类似,但是也有区别的地方,在上一个设计模式,我们学习的是仲裁者模式,其中当控件的状态发生改变的时候就会向仲裁者发出信息,让仲裁者进行仲裁,这其实和发布订阅非常的类似,但是用处是不一样的,仲裁者模式是用来解除复杂对象之间的相互调用的关系,从而独立出来进行开发,而观察者模式是在被观察者状态改变的时候被动的被唤醒进行相应的处理,两者的实现比较类似,比如都是被动唤醒的,但是思想和用处是不一样的,被唤醒之后的处理是不一样的。

二、代码

  首先我们自己实现观察者模式,其次我们使用java已经实现好的观察者接口,然后来对比一下两者的不同。

  2.1、自己实现观察者模式

 NumberGenerator 类:
 package zyr.dp.observer;

 import java.util.ArrayList;
import java.util.Iterator; public abstract class NumberGenerator { private ArrayList observers=new ArrayList(); public void add(Observer observer){
observers.add(observer);
}
public void remove(Observer observer){
observers.remove(observer);
}
public void notifyObserver(){
Iterator it=observers.iterator();
while(it.hasNext()){
Observer object=(Observer)it.next();
object.update(this);
}
}
public abstract void execuate();
public abstract int getNumber();
}
RandomNumberGenerator 类:
 package zyr.dp.observer;

 import java.util.Random;

 public class RandomNumberGenerator extends NumberGenerator {

     private Random random=new Random();
private int number;
public int getNumber(){
return number;
}
public void execuate() {
for(int i=0;i<20;i++){
number=random.nextInt(60);
notifyObserver();
}
} }

  Observer接口:

 package zyr.dp.observer;

 public interface Observer {
public abstract void update(NumberGenerator object);
}

  DigitalObserver类:

 package zyr.dp.observer;

 public class DigitalObserver implements Observer {

     public void update(NumberGenerator object) {
System.out.println("DigitalObserver:"+object.getNumber());
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
} }

  GraphObserver类:

 package zyr.dp.observer;

 public class GraphObserver implements Observer {

     public void update(NumberGenerator object) {
System.out.print("GraphObserver:");
for(int i=0;i<object.getNumber();i++){
System.out.print("*");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println();
} }

  Main类:

 package zyr.dp.observer;

 public class Main {

     public static void main(String[] args) {
NumberGenerator numberGenerator=new RandomNumberGenerator();
numberGenerator.add(new DigitalObserver());
numberGenerator.add(new GraphObserver()); numberGenerator.execuate();
} }

运行结果:

DigitalObserver:20
GraphObserver:********************
DigitalObserver:56
GraphObserver:********************************************************
DigitalObserver:11
GraphObserver:***********
DigitalObserver:52
GraphObserver:****************************************************
DigitalObserver:54
GraphObserver:******************************************************
DigitalObserver:41
GraphObserver:*****************************************
DigitalObserver:39
GraphObserver:***************************************
DigitalObserver:14
GraphObserver:**************
DigitalObserver:18
GraphObserver:******************
DigitalObserver:35
GraphObserver:***********************************
DigitalObserver:40
GraphObserver:****************************************
DigitalObserver:3
GraphObserver:***
DigitalObserver:0
GraphObserver:
DigitalObserver:43
GraphObserver:*******************************************
DigitalObserver:29
GraphObserver:*****************************
DigitalObserver:2
GraphObserver:**
DigitalObserver:48
GraphObserver:************************************************
DigitalObserver:0
GraphObserver:
DigitalObserver:48
GraphObserver:************************************************
DigitalObserver:40
GraphObserver:****************************************

运行结果

    由此可以看到当被观察者的状态发生改变的时候会主动通知观察者,使用notifyObserver的方法将自己的状态传递过去,因为是自己定义的被观察者的抽象类以及接口,因此使用起来非常的方便。代码也不是很多,能够按照自己的要求来完成更新操作,对比于仲裁者模式,被观察者是主动将自己的内容传递给观察者的,而仲裁者模式中,组员是本身就已经组合(委托)进了仲裁者之中,这也是一点不同。代码比较简单,这里被观察者使用了抽象类而不使用接口的原因是需要定义对观察者对象的委托,因此使用了抽象类,而观察者只用了update方法将被观察者通过参数传递的方式委托进来,因此使用接口更加清晰一点,当然抽象类也可以,只不过能使用接口的就不要使用抽象类,因为一个类只能继承一个父类,但是可以实现很多接口。

  2.2、使用java自带的观察者模式

RandomNumberGenerator 类:
 package zyr.dp.java;

 import java.util.Observable;
import java.util.Random; public class RandomNumberGenerator extends Observable {

private Random random=new Random();
private int number;
public int getNumber(){
return number;
}
public void execuate() {
for(int i=0;i<20;i++){
number=random.nextInt(60);
setChanged();
notifyObservers();
}
} }

  DigitalObserver类:

 package zyr.dp.java;

 import java.util.Observable;
import java.util.Observer; public class DigitalObserver implements Observer { public void update(Observable object, Object arg) {
System.out.println("DigitalObserver为:"+((RandomNumberGenerator)object).getNumber());
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
} }
GraphObserver 类:
 package zyr.dp.java;

 import java.util.Observable;
import java.util.Observer; public class GraphObserver implements Observer { public void update(Observable object, Object arg) {
System.out.print("GraphObserver为:");
for(int i=0;i<((RandomNumberGenerator)object).getNumber();i++){
System.out.print("*");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println();
} }

 Main类:

 package zyr.dp.java;

 import java.util.Observable;

 public class Main {

     public static void main(String[] args) {
Observable observable=new RandomNumberGenerator();
observable.addObserver(new DigitalObserver());
observable.addObserver(new GraphObserver()); ((RandomNumberGenerator)observable).execuate();
} }

     可以看到在java自定义的观察者模式之中,首先要修改 setChanged();来使得notifyObservers生效,其次,传递的参数不是很灵活,需要强制转换成我们想要的东西,最后在使用的时候也需要强制转换,这是比较麻烦的,并且被观察者也是继承了抽象类Observable,不方便以后功能的扩展,如果以后再想继承其它的类就很困难了。我们自己设计的时候,可以使用某些方式把抽象类变成接口,不过也需要一定的操作。

 三、总结

    通过观察者模式使得观察者和被观察者之间面向抽象编程,观察者不用知道自己观察的对象到底是谁的实例,只需要知道这个对象继承了被观察者的抽象类,因此当被观察者增加的时候,观察者可以不用修改。同样的,对于被观察者的实例来说,并不需要知道自己到底是被哪一个观察者观察了,只需要知道观察自己的观察者肯定使用了观察者的接口,因此观察者和被观察者之间通过面向抽象编程提高了可扩展性,便于组件化。

    我们可以看到在面向对象编程中能够使用委托(组合)的就不要使用继承,委托是弱关联,继承是强关联。并且将一些共同操作抽象出来放到抽象类之中去定义,在参数传递中不使用具体类型而是用接口或者抽象类,这样的设计思想便于组件化,具有可替换性。

  程序代码

设计模式:观察者(Observer)模式的更多相关文章

  1. 面向对象设计模式——观察者(OBSERVER)模式

    定义 定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新.  Observer模式描述了如何建立这种关系.这一模式中的关键对象是目标(subject ...

  2. Java 实现观察者(Observer)模式

    1. Java自带的实现 类图 /** * 观察目标 继承自 java.util.Observable * @author stone * */ public class UpdateObservab ...

  3. 设计模式C++描述----04.观察者(Observer)模式

    一. 概述 Observer 模式要解决的问题为:建立一个一(Subject)对多(Observer)的依赖关系,并且做到当“一”变化的时候,依赖这个“一”的多也能够同步改变. Sbuject 相当于 ...

  4. Java设计模式之从[星际争霸的兵种升级]分析观察者(Observer)模式

    观察者模式定义对象的一种一对多的依赖关系.当一个对象的状态发生改变时.全部依赖于它的对象都会得到通知并被自己主动更新. 一个简单的样例是.在星际争霸的虫族中有一个0基础单位叫做跳狗(Zergling) ...

  5. 设计模式--观察者(Observer)

    GOF给出的定义: Define a one-to-many dependency between objects so that when one object changes state, all ...

  6. 设计模式之——Observer模式

    Observer模式又叫做观察者模式,当观察对象状态发生变化的时候,就会通知给观察者.这种模式适用于根据对象状态进行响应的场景! 实例程序是一个输出数字的程序. 观察者Observer类用于每500m ...

  7. 观察者(Observer)模式

    观察者模式又叫做发布-订阅模式(Publish.Subscribe)模式.模型-视图模式(Model/View)模式.源-监听器模式(Source/Listener)模式或从属者(Dependents ...

  8. 3)Javascript设计模式:Observer模式

    Observer模式 var Observer = (function() { var instance = null; function Observe() { this.events = {} } ...

  9. 设计模式之观察者(OBSERVER)模式

    定义 定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新.  Observer模式描述了如何建立这种关系.这一模式中的关键对象是目标(subject ...

  10. Head First 设计模式 —— 02. 观察者 (Observer) 模式

    思考题 在我们的一个实现中,下列哪种说法正确?(多选) P42 public class WeatherDate { // 实例变量声明 public void measurementsChanged ...

随机推荐

  1. 后台如何通过Request取得多个含有相同name的控件的值?

    在Asp.net开发中,所有html控件的值都是可以在服务器端用后台代码的Request[name]来获取其值的.但如果有多个相同name的Html控件提交到后台,怎么分别取各个控件的值呢?而多数情况 ...

  2. 如何自定义修改ztree树节点的图标

    1.此种情况是针对后对数据没有不好判断谁是父节点和子节点的问题 ztree默认的树节点,父子节点的图标不大好看,修改图片只需要在数据的地方添加icon的键,值就是图片的相对位置,但是问题就是需要区分是 ...

  3. 游戏中的网络同步机制——Lockstep(帧同步)

    本文来自: https://bindog.github.io/blog/2015/03/10/synchronization-in-multiplayer-networked-game-lockste ...

  4. Tomcat与Nginx的整合

    Tomcat与Nginx的整合 环境 操作系统:ubuntu 14.04.4 LTS 安装Nginx 有两种方式,一种是使用apt-get命令来安装二进制版本,另外一种是下载源码后自己编译. 二进制安 ...

  5. 江铖:乳腺癌识别By AI

    欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由云加社区技术沙龙 发表于云+社区专栏 演讲嘉宾:江铖,腾讯觅影高级研究员.多年以来一直从事计算机视觉相关的研究.加入腾讯以后,负责腾讯 ...

  6. Python基础(4) - 变量

    Python 命名规则: 变量名必须是字母或者_开头. 变量名的其他部分可以是字母,_或者数字. Python是大小写敏感的. 以下划线开头的标识符是有特殊意义: 以单下划线开头(_foo)的代表不能 ...

  7. React.js 小书 Lesson23 - dangerouslySetHTML 和 style 属性

    作者:胡子大哈 原文链接:http://huziketang.com/books/react/lesson23 转载请注明出处,保留原文链接和作者信息. 这一节我们来补充两个之前没有提到的属性,但是在 ...

  8. 《C++ Primer》〓〓〓〓〓〓〓〓〓〓【第七章】

    7.5.1 构造函数初始化列表 如果成员是const.引用,或者属于某种未提供默认构造函数的类类型,我们必须通过构造函数初始值列表为这些成员提供初值. 成员的初始化顺序与他们在类定义中的出现顺序一致. ...

  9. 【关于eclipse的一些自己常用的插件】

    代码自动走查: sonarlnt:

  10. [转]微信小程序填坑之路之使用localhost在本地测试

    本文转自:http://www.wxappclub.com/topic/798