JAVA设计模式之观察者模式

一、观察者模式简介

Observer模式是行为模式之一,它的作用是当一个对象的状态发生变化时,能够自动通知其他关联对象,自动刷新对象状态。
Observer模式提供给关联对象一种同步通信的手段,使某个对象与依赖它的其他对象之间保持状态同步。

二、观察者模式的结构

在这里插入图片描述

三、观察者模式角色与职责

  1. Subject(被观察者): 被观察的对象。当需要被观察的状态发生变化时,需要通知队列中所有观察者对象。Subject需要维持(添加,删除,通知)一个观察者对象的队列列表。
  2. ConcreteSubject : 被观察者的具体实现。包含一些基本的属性状态及其他操作。
  3. Observer(观察者):接口或抽象类。当Subject的状态发生变化时,Observer对象将通过一个callback函数得到通知。
  4. ConcreteObserver :观察者的具体实现。得到通知后将完成一些具体的业务逻辑处理。

四、观察者模式的具体实现

Internet气象站项目:

  1. 提供温度、气压和湿度的接口
  2. 测量数据更新时需时时通知给第三方
  3. 需要设计开放型API,便于其他第三方公司也能接入气象站获取数据

1、不使用观察者模式

方案设计:

Current当前温度信息类Weather天气信息类
update()getTem()
display()getHum()
-getPre()
-dataChange()

在Weather类中,当发生数据变化,调用dataChange()方法时,同时通知Current类中的update()方法,并调用display()方法打印出天气。
Weather类代码示例:

// An highlighted block
package design.sob.gys.nosob;
public class Weather {
private float tem;
private float hum;
private float pre;
private Current current;
public Weather(Current current) {
 this.current=current;
}
public float getTem() {
 return tem;
}
public void setTem(float tem) {
 this.tem = tem;
 dataChange();
}
public float getHum() {
 return hum;
}
public void setHum(float hum) {
 this.hum = hum;
 dataChange();
}
public float getPre() {
 return pre;
}
public void setPre(float pre) {
 this.pre = pre;
 dataChange();
}
public void setAll(float tem,float hum,float pre)
{
 this.tem=tem;
 this.hum=hum;
 this.pre=pre;
 dataChange();
}
public void dataChange()
{
 current.update(getTem(),getHum(),getPre());
}
}

我们在每次天气信息有变化时都通知Current类,并主动推送天气信息。接下来是定义Currnet类:

// An highlighted block
package design.sob.gys.nosob;
public class Current {
 private float tem;
 private float hum;
 private float pre;
 public void update(float tem,float hum,float pre) {
  this.tem=tem;
  this.hum=hum;
  this.pre=pre;
  display();
 }
 public void display() {
  System.out.println("今日温度"+tem);
  System.out.println("今日适度"+hum);
  System.out.println("今日气压"+pre);
 }
}

Current类中只有两个方法,接受更新,并且打印信息。
在这个代码中,若是我们想要增加天气预报类,那么需要在定义Weather类时,需要增加构造方法的参数,当显示天气的类较多时,代码需要大量修改,无法在运行时动态添加,代码的可用性差。
接下来实现观察者模式。

2、使用观察者模式

对象之间多对一依赖的一种设计方案,被依赖的对象为Subject,依赖的对象为Observer,Subject通知Observer变化。

方案设计:

接口设计

SubjectObserver
registerOb()登记update()更新
removeOb()移除-
notifaOb()通知-

Subject 接口:

// An highlighted block
package design.sob.gys.subject;
import design.sob.gys.observer.Observer;
public interface Subject {
void registerOb(Observer o);
 void removeOb(Observer o);
 void notifyOb();
}

Observer接口:

// An highlighted block
package design.sob.gys.observer;
public interface Observer {
 void update(float tem, float hum, float pre);
}

实现类设计

Weather implement SubjectCurrent implement ObserverForecast implement Observer
registerOb()update()update
removeOb()display()display()
notifyOb()--
getTem()--
getHum()--
getPre()--

Weather类实现Subject接口:

// An highlighted block
package design.sob.gys.subject;
import java.util.LinkedList;
import design.sob.gys.observer.Observer;
public class Weather implements Subject{
 private float tem;
 private float hum;
 private float pre;
 private LinkedList<Observer> observers;//使用LinkedList存储注册用户
 public Weather() {
  super();
  observers=new LinkedList<Observer>();
 }
 @Override
 public void registerOb(Observer o) {
  // TODO Auto-generated method stub
  observers.add(o);
 }
 @Override
 public void removeOb(Observer o) {
  // TODO Auto-generated method stub
  observers.remove(o);
 }
 @Override
 public void notifyOb() {
  // TODO Auto-generated method stub
  for(Observer o :observers)
   o.update(getTem(),getHum(),getPre());
 }
 public float getTem() {
  return tem;
 }
 public void setTem(float tem) {
  this.tem = tem;
  notifyOb();
 }
 public float getHum() {
  return hum;
 }
 public void setHum(float hum) {
  this.hum = hum;
  notifyOb();
 }
 public float getPre() {
  return pre;
 }
 public void setPre(float pre) {
  this.pre = pre;
  notifyOb();
  }
  public void setAll(float tem,float hum,float pre) {
  this.tem=tem;
  this.hum=hum;
  this.pre=pre;
  notifyOb();
 }
}

Current类实现Observer接口:

// An highlighted block
package design.sob.gys.observer;
public class Current implements Observer{
 private float tem;
 private float hum;
 private float pre;
 @Override
 public void update(float tem, float hum, float pre) {
  this.tem=tem;
  this.hum=hum;
  this.pre=pre;
  display();
 }
 public void display() {
  System.out.println("今日温度"+tem);
  System.out.println("今日湿度"+hum);
  System.out.println("今日气压"+pre);
 }
}

Forecast类实现Observer接口:

// An highlighted block
package design.sob.gys.observer;
public class Forecast implements Observer{
 private float tem;
 private float hum;
 private float pre;
 @Override
 public void update(float tem, float hum, float pre) {
  this.tem=tem;
  this.hum=hum;
  this.pre=pre;
  display();
 }
 public void display() {
  System.out.println("明日温度"+(tem+1.5));
  System.out.println("明日湿度"+(hum+12));
  System.out.println("明日气压"+(pre-5));
 }
}

测试程序:通过创建两个观察者current和forecast,并注册到weather对象中,每次天气更新,weather对象将发送信息到观察者,并显示。

// An highlighted block
package design.sob.gys.subject;
import design.sob.gys.observer.Current;
import design.sob.gys.observer.Forecast;
public class Testsob {
public static void main(String[] args) {
  Current current =new Current();
  Weather weather =new Weather();
  weather.registerOb(current);
  weather.setAll(38, 54, 112);
  Forecast forecast=new Forecast();
  weather.registerOb(forecast);
  System.out.println("--------");
  weather.setAll(25, 67, 115);
  System.out.println("--------");
  weather.setHum(78);
  weather.removeOb(current);
  System.out.println("--------");
  weather.notifyOb();
 }
}

以下是测试输出:

// An highlighted block
今日温度38.0
今日湿度54.0
今日气压112.0
--------
今日温度25.0
今日湿度67.0
今日气压115.0
明日温度26.5
明日湿度79.0
明日气压110.0
--------
今日温度25.0
今日湿度78.0
今日气压115.0
明日温度26.5
明日湿度90.0
明日气压110.0
--------
明日温度26.5
明日湿度90.0
明日气压110.0

可以看到,观察者模式可以灵活的接入其他对象,保证Weather实现不用每次更新。

五、Java内置观察者模式

内置观察者模式有两种方案:

  1. 消息通知,并推送消息
  2. 消息通知,观察者拉去消息

1、类 Observable

public class Observableextends Object此类表示模型视图范例中的 observable 对象,或者说“数据”。可将其子类化,表示应用程序想要观察的对象。

一个 observable 对象可以有一个或多个观察者。观察者可以是实现了 Observer 接口的任意对象。一个 observable 实例改变后,调用 Observable 的 notifyObservers 方法的应用程序会通过调用观察者的 update 方法来通知观察者该实例发生了改变。

未指定发送通知的顺序。Observable 类中所提供的默认实现将按照其注册的重要性顺序来通知 Observers,但是子类可能改变此顺序,从而使用非固定顺序在单独的线程上发送通知,或者也可能保证其子类遵从其所选择的顺序。

注意,此通知机制与线程无关,并且与 Object 类的wait 和 notify 机制完全独立。 新创建一个 observable 对象时,其观察者集是空的。当且仅当 equals 方法为两个观察者返回 true 时,才认为它们是相同的。

类方法
返回值方法名方法说明
voidaddObserver(Observer o)如果观察者与集合中已有的观察者不同,则向对象的观察者集中添加此观察者。
protectedvoid clearChanged()指示对象不再改变,或者它已对其所有的观察者通知了最近的改变,所以 hasChanged 方法将返回 false。
intcountObservers()返回 Observable 对象的观察者数目。
voiddeleteObserver(Observer o)从对象的观察者集合中删除某个观察者。
voiddeleteObservers()清除观察者列表,使此对象不再有任何观察者。
booleanhasChanged()测试对象是否改变。
voidnotifyObservers()如果 hasChanged 方法指示对象已改变,则通知其所有观察者,并调用 clearChanged 方法来指示此对象不再改变。
voidnotifyObservers(Object arg)如果 hasChanged 方法指示对象已改变,则通知其所有观察者,并调用 clearChanged 方法来指示此对象不再改变。
protectedvoid setChanged()标记此 Observable 对象为已改变的对象;现在hasChanged 方法将返回 true。

2、接口 Observer

public interface Observer一个可在观察者要得到 observable 对象更改通知时可实现 Observer 接口的类。

接口方法
返回值方法名方法说明
voidupdate(Observable o, Object arg)只要改变了 observable 对象就调用此方法。

3、内置观察者实现

仍然实现我们之前的天气预报例子。
我们首先定义一个用来保存天气信息的Data类:

// An highlighted block
package design.sob.gys.innernob;
public class Data {
 private float tem;
 private float hum;
 private float pre;
 public float getTem() {
  return tem;
 }
 public void setTem(float tem) {
  this.tem = tem;
 }
 public float getHum() {
  return hum;
 }
 public void setHum(float hum) {
  this.hum = hum;
 }
 public float getPre() {
  return pre;
 }
 public void setPre(float pre) {
  this.pre = pre;
 }
}

注意,Observable有一个setChanged()方法,该方法返回一个boolean值,用来检测是否发生变化,在改变信息时,需要设置改boolean值并在传递消息结束后清除clearChanged()。
继承Observable类的Weather类:

// An highlighted block
package design.sob.gys.innernob;
import java.util.Observable;
public class Weather extends Observable{
 private Data data;
 public Weather() {
  super();
  data = new Data();
 }
 public float getTem() {
  return data.getTem();
 }
 public void setTem(float tem) {
  data.setTem(tem);
  this.setChanged();// 设置Boolean值 
  this.notifyObservers(data);
  this.clearChanged();//清除Boolean值
 }
 public float getHum() {
  return data.getHum();
 }
 public void setHum(float hum) {
  data.setHum(hum);
  this.setChanged();
  this.notifyObservers(data);
  this.clearChanged();
 }
 public float getPre() {
  return data.getPre();
 }
 public void setPre(float pre) {
  data.setPre(pre);
  this.setChanged();
  this.notifyObservers(data);
  this.clearChanged();
 }
 public void setAll(float tem,float hum,float pre) {
  data.setTem(tem);
  data.setHum(hum);
  data.setPre(pre);
  this.setChanged();
  this.notifyObservers(data);
  this.clearChanged();
 }
}

实现Observer接口的Current类:

// An highlighted block
package design.sob.gys.innernob;
import java.util.Observable;
import java.util.Observer;
public class Current implements Observer{
private float tem;
private float hum;
private float pre;
 @Override
 public void update(Observable o, Object arg) {
  // TODO Auto-generated method stub
  this.tem=((Data)(arg)).getHum();
  this.hum=((Data)(arg)).getTem();
  this.pre=((Data)(arg)).getPre();
  display();
 }
 public void display() {
  System.out.println("今日温度"+tem);
  System.out.println("今日湿度"+hum);
  System.out.println("今日气压"+pre);
  }
}

实现Observer接口的Forecast类:

// An highlighted block
package design.sob.gys.innernob;
import java.util.Observable;
import java.util.Observer;
public class Forecast implements Observer{
private float tem;
private float hum;
private float pre;
@Override
public void update(Observable o, Object arg) {
this.tem=((Data)(arg)).getHum();
this.hum=((Data)(arg)).getTem();
this.pre=((Data)(arg)).getPre();
display();
 }
public void display() {
System.out.println("明日温度"+(tem+2.4));
System.out.println("明日湿度"+(hum-12));
System.out.println("明日气压"+(pre+10));
 }
}

测试内置观察者模式:

// An highlighted block
package design.sob.gys.innernob;
public class Testinnersob {
 public static void main(String[] args) {
  // TODO Auto-generated method stub
  Current current =new Current();
  Forecast forecast = new Forecast();
  Weather weather=new Weather();
  weather.addObserver(current);
  weather.addObserver(forecast);
  weather.setAll(24, 45, 112);
  System.out.println("---------");
  weather.setPre(100);
  System.out.println("---------");
  weather.deleteObserver(current);
  weather.setTem(-10);
  }
}

测试结果输出如下:

// An highlighted block
明日温度47.4
明日湿度12.0
明日气压122.0
今日温度45.0
今日湿度24.0
今日气压112.0
---------
明日温度47.4
明日湿度12.0
明日气压110.0
今日温度45.0
今日湿度24.0
今日气压100.0
---------
明日温度47.4
明日湿度-22.0
明日气压110.0

可以看到,内置观察者的输出顺序与原来的不一致,原来使用LinkedList,先进先出。

六、Observer模式的典型应用

  • 侦听事件驱动程序设计中的外部事件
  • 侦听/监视某个对象的状态变化
  • 发布者/订阅者(publisher/subscriber)模型中,当一个外部事件(新的产品,消息的出现等等)被触发时,通知邮件列表中的订阅者

要抱抱才会开心呀~~~~~~~~~~~

要抱抱才会开心呀

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值