首页 » 软件开发 » 一文带你彻底搞懂发布与订阅设计(观察者主题对象状态角色)

一文带你彻底搞懂发布与订阅设计(观察者主题对象状态角色)

乖囧猫 2024-07-24 14:56:06 0

扫一扫用手机浏览

文章目录 [+]

一、介绍

我们常说的发布订阅设计模式,也叫观察者模式,也就是事件监听机制,观察者模式订阅了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象,当这个主题对象发生改变时,会通知所有的观察者对象,使他们能够自动的更新自己!

一个软件系统要求某个对象在发生变化时,某些其他的对象作出相应的改变,能做到这点的设计方案有很多,但观察者模式是满足这一要求的各种设计方案中最重要的一种。

从整体来看,观察者模式所涉及的角色有:

一文带你彻底搞懂发布与订阅设计(观察者主题对象状态角色) 软件开发
(图片来自网络侵删)
抽象主题角色:抽象主题角色把所有对观察者对象的引用保存在一个集合中,每个主题都可以有任意数量的观察者。
抽象主题提供一个接口,可以增加和删除观察者对象;具体主题角色:将有关状态存入具体观察者对象,在具体主题的内部状态改变时,给所有登记过的观察者发出通知;抽象观察者角色:为所有的具体观察者提供一个接口,在得到主题通知时更新自己;具体观察者角色:存储与主题的状态相关的状态。
具体观察者角色实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态协调

废话也不多说了,下面我们直接讲案例!

二、示例

抽象主题角色,有增加观察者、删除观察者、通知观察者的功能,内容如下:

public abstract class AbstractSubject { / 用来保存注册的观察者对象 / private List<Observer> list = new ArrayList<Observer>(); / 注册观察者对象 / public void add(Observer observer){ list.add(observer); System.out.println("add an observer"); } / 删除观察者对象 @param observer / public void remove(Observer observer){ list.remove(observer); System.out.println("delete an observer"); } / 通知所有注册的观察者对象 @param state / public void notifyObservers(String state){ for (int i = 0; i < list.size(); i++) { list.get(i).update(state); } }}

具体主题角色,这个change方法放在子类中是因为可能不同的主题在改变观察者状态的时候会做一些不同的操作,因此就不统一放在父类Subject里面了,内容如下:

public class ConcreteSubject extends AbstractSubject{ private String state; public void change(String newState){ state = newState; System.out.println("主题状态:" + state); //状态发生改变,通知所有的观察者 super.notifyObservers(state); }}

观察者接口,内容如下:

public interface Observer { / 修改状态 @param state / void update(String state);}

具体观察者实现了观察者接口,内容如下:

public class ConcreteObserver implements Observer{ @Override public void update(String state) { System.out.println("观察者,收到状态:" + state); }}

客户端调用代码,一旦主题调用了change方法改变观察者的状态,那么观察者Observer里面的observerState全都改变了,内容如下:

public class ObserverClient { public static void main(String[] args) { //创建一个主题角色 ConcreteSubject subject = new ConcreteSubject(); //创建观察者对象 ConcreteObserver observer = new ConcreteObserver(); //将观察者加入主题对象上 subject.add(observer); //改变主题状态 subject.change("hello world"); }}

运行结果如下:

add an observer主题状态:hello world观察者,收到状态:hello world

这里只添加了一个观察者,有兴趣的可以试试看多添加几个观察者,效果都是一样的,主题角色改变状态,观察者状态全变。

三、应用

观察者模式的两种模型

推模型:主题对象向观察者推送主题的详细信息,不管观察者是否需要。
推送的信息通常是主题对象的全部或部分数据,上面的例子就是典型的推模型。
拉模型:主题对象在通知观察者的时候,只传递少量信息。
如果观察者需要更具体的信息,由观察者主动到主题对象中去获取,相当于是观察者从主题对象中拉数据。
一般这种模型的实现中,会把主题对象自身通过update()方法传递给观察者,这样观察者在需要获取数据的时候,就可以通过这个引用来获取了。

两种模型的比较

1、推模型是假设主题对象知道观察者需要的数据,拉模型是假设主题对象不知道观察者需要什么数据,干脆把自身传递过去,让观察者自己按需要取值。
2、推模型可能会使得观察者对象难以复用,因为观察者的update()方法是按需要定义的参数,可能无法兼顾到没有考虑到的使用情况,这意味着出现新的情况时,可能要提供新的update()方法。

JDK是有直接支持观察者模式的,就是java.util.Observer这个接口,内容如下:

public interface Observer { / This method is called whenever the observed object is changed. An application calls an <tt>Observable</tt> object's <code>notifyObservers</code> method to have all the object's observers notified of the change. @param o the observable object. @param arg an argument passed to the <code>notifyObservers</code> method. / void update(Observable o, Object arg);}

这就是观察者的接口,定义的观察者只需要实现这个接口就可以了。
update()方法,被观察者对象的状态发生变化时,被观察者的notifyObservers()方法就会调用这个方法,内容如下:

public class Observable { private boolean changed = false; private Vector obs; / Construct an Observable with zero Observers. / public Observable() { obs = new Vector(); } / Adds an observer to the set of observers for this object, provided that it is not the same as some observer already in the set. The order in which notifications will be delivered to multiple observers is not specified. See the class comment. @param o an observer to be added. @throws NullPointerException if the parameter o is null. / public synchronized void addObserver(Observer o) { if (o == null) throw new NullPointerException(); if (!obs.contains(o)) { obs.addElement(o); } } ...}

这是被观察者的父类,也就是主题对象。
这是一个线程安全的类,是基于Vector实现的。

创建一个观察者,内容如下:

import java.util.Observable;import java.util.Observer;public class Watched implements Observer { @Override public void update(Observable o, Object arg) { System.out.println("观察者,收到状态:" + arg); }}

创建一个主题,内容如下:

import java.util.Observable;public class Subject extends Observable { private String data; public void setData(String newData){ System.out.println("主题状态:" + newData); data = newData; setChanged(); notifyObservers(data); }}

写一个main函数调用,内容如下:

public class WatchedClient { public static void main(String[] args) { //创建观察者对象 Watched watched = new Watched(); //创建主题 Subject subject = new Subject(); //将观察者对象加入主题 subject.addObserver(watched); //修改主题状态 subject.setData("hello world"); }}

运行结果,内容如下:

主题状态:hello world观察者,收到状态:hello world

看到主题对象改变的时候,观察者对象的状态也随之改变。

四、总结

引入设计模式最主要的作用我认为就是两点:

去重复代码,使得代码更清晰、更易读、更易扩展解耦,使得代码可维护性更好,修改代码的时候可以尽量少改地方

使用观察者模式可以很好地做到这两点。
增加观察者,直接new出观察者并注册到主题对象之后就完事了,删除观察者,主题对象调用方法删除一下就好了,其余都不用管。
主题对象状态改变,内部会自动帮我们通知每一个观察者,是不是很方便呢?

观察者模式主要应用场景有:

对一个对象状态的更新需要其他对象同步更新对象仅需要将自己的更新通知给其他对象而不需要知道其他对象的细节,如消息推送

相关文章

语言中的借用,文化交融的桥梁

自古以来,人类社会的交流与发展离不开语言的传播。在漫长的历史长河中,各民族、各地区之间的文化相互碰撞、交融,产生了许多独特的语言现...

软件开发 2025-01-01 阅读1 评论0

机顶盒协议,守护数字生活的新卫士

随着科技的飞速发展,数字家庭逐渐走进千家万户。在这个时代,机顶盒成为了连接我们与丰富多彩的数字世界的重要桥梁。而机顶盒协议,作为保...

软件开发 2025-01-01 阅读1 评论0

语言基础在现代社会的重要性及方法步骤

语言是人类沟通的桥梁,是社会发展的基础。语言基础作为语言学习的基石,对于个人、社会乃至国家的发展具有重要意义。本文将从语言基础在现...

软件开发 2025-01-01 阅读2 评论0

粤语电影,传承文化,点亮时代之光

粤语电影,作为中国电影产业的一朵奇葩,以其独特的地域特色、丰富的文化内涵和鲜明的艺术风格,赢得了广大观众的喜爱。本文将从粤语电影的...

软件开发 2025-01-01 阅读3 评论0

苹果游戏语言,塑造未来娱乐体验的基石

随着科技的飞速发展,游戏产业逐渐成为全球娱乐市场的重要支柱。在我国,游戏产业更是蓬勃发展,吸引了无数玩家和投资者的目光。而在这其中...

软件开发 2025-01-01 阅读1 评论0