java开发模式之观察者模式,设计模式之观察者模式

引言

观察者模式是行为型设计模式的一种。当我们对一个对象的状态感兴趣,并且当它状态发生改变时想要得到变化的信息,在这种情况下,观察者模式是非常有用的。在观察者模式中,观察其他对象状态的对象被称为 Observer,被监视的那个对象被称为 Subject。

根据 GoF(《设计模式》的四个作者,被称为四人组,Gang of Four)所说,观察者模式的定义是:

在对象之间定义一个一对多的依赖,这样依赖,当一个对象改变状态,依赖它的对象会收到通知并自动更新。

Subject 包含了一个 observers 的列表,当其状态发生改变时会通知它们。所以 Subject 应该提供一个方法让 observers 可以向 Subject 注册或者注销自己,还应该包含一个可以通知所有 observers 的方法。在通知 observers 时, Subject 可以将更新发送给 observers,也可以提供一个方法让 observers 获取更新。

Observer 应该有一个方法可以设置需要观察的对象,还应该提供方法供 Subject 调用,让 Subject 将更新内容发送过来。

Java 内部提供了观察者模式的实现,主要是通过 java.util.Observable 类和 java.util.Observer 接口实现。可以这个实现并没有被广泛的使用,因为它的实现过于简单。由于 java 不支持多继承,因此在大多数情况下,我们不会通过继承一个类来实现观察这模式。

观察者模式例子

在我们用 java 实现的观察者模式中,我们将会实现一个简单的 topic 和几个可以注册 topic 的 observer。当 topic 有新的话题之后,所有注册的 observer 都会被通知。

Subject 接口是必须的,我们这里提供的是一个基本的 Subject 接口,这个接口定义了一些方法让具体的 Subject 类实现。

public interface Subject{

// 注册和注销 observers 的方法

public void register(Observer obj);

public void unregister(Observer obj);

// 通知 observers 的方法

public void notifyObservers();

// 从 Subject 获取更新

public Object getUpdate(Observer obj);

}

接下来我们会创建 Observer。这个类有两个方法,一个方法是将 Subject 和 observer 联系起来,另一个方法是让 Subject 使用的,方便其将改变的信息通知给所有的 observer。

public interface Observer{

// 更新 observer,提供给 subject 使用

public void update();

// 将 subject 和 observe 联系起来

public void setSubject(Subject sub);

}

整体的架构已经准备好了,现在开始创建 topic 的具体实现。

import java.util.ArrayList;

import java.util.List;

public class MyTopic implements Subject{

private List observers;

private String message;

private boolean changed;

private final Object MUTEX = new Object();

public MyTopic(){

this.observers = new ArrayList<>();

}

@Override

public void register(Observer obj){

if(obj == null)

throw new NullPointerException("Null Observer");

synchronized(MUTEX){

if(!observers.contains(obj))

observers.add(obj);

}

}

@Override

public void unregister(Observer obj){

synchronized(MUTEX){

observers.remove(obj);

}

}

@Override

public void notifyObservers(){

List observersLocal = null;

// 使用 synchronized 主要是为了确保在消息更细之后的 observer 不会被通知到

synchronized(MUTEX){

if(!changed)

return ;

observersLocal = new ArrayList<>(this.observers);

this.changed = false;

}

for(Observer obj : observersLocal){

obj.update();

}

}

@Override

public Object getUpdate(Observer obj){

return this.message;

}

// 往该主题添加消息

public void postMessage(String msg){

System.out.println("Message Posted to Topic:" + msg);

this.message = msg;

this.changed = true;

notifyObservers();

}

}

注册和注销 observer 的方法是很简单的,就不做过多的阐述。这里说一下 postMessage 方法,该方法是被应用程序所使用的,发送更新的信息给 topic。注意类中 boolean 类型的局部变量,它主要是跟踪 topic 的状态,在通知 observer 时会被用到。这个变量是有必要的,为了防止 topic 没有更新数据时,有人调用 notifyObservers 方法。

同时注意一下 notifyObservers 方法中使用了 synchronized 关键字,这主要是为了确保把消息发送给那些已经注册的用户,消息产生后才注册的 observer 不会收到更新。

这是 Observer 的具体实现:

public class MyTopicSubscriber implements Observer{

private String name;

private Subject topic;

public MyTopicSubscriber(String nm){

this.name = nm;

}

@Override

public void update(){

String msg = (String) topic.getUpdate(this);

if(msg == null){

System.out.println(name + ":: No new message");

}else{

System.out.println(name + ":: Consuming message" + msg);

}

}

@Override

public void setSubject(Subject sub){

this.topic = sub;

}

}

接下来我们写一下简单的小例子使用一下观察者模式:

public class ObserverPatternTest {

public static void main(String[] args){

// 创建 subject

MyTopic topic = new MyTopic();

// 创建 observers

Observer obj1 = new MyTopicSubscriber("Obj1");

Observer obj2 = new MyTopicSubscriber("Obj2");

Observer obj3 = new MyTopicSubscriber("Obj3");

// 向 subject 注册 observer

topic.register(obj1);

topic.register(obj2);

topic.register(obj3);

// 将 observer 和 subject 联系起来

obj1.setSubject(topic);

obj2.setSubject(topic);

obj3.setSubject(topic);

// 检查是否可以获取所有更新

obj1.update();

// 向 subject 发送更新数据

topic.postMessage("New Message");

}

}

运行程序之后,我们会得到这样的输出。

Obj1:: No new message

Message Posted to Topic:New Message

Obj1:: Consuming messageNew Message

Obj2:: Consuming messageNew Message

Obj3:: Consuming messageNew Message

观察者模式类图

观察者模式也被称为 订阅-发布 模式。这是一些主流技术中的实现:

java.util.EventListener in Swing

javax.servlet.http.HttpSessionBindingListener

javax.servlet.http.HttpSessionAttributeListener

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值