观察者设计模式示例

本文是我们名为“ Java设计模式 ”的学院课程的一部分。

在本课程中,您将深入研究大量的设计模式,并了解如何在Java中实现和利用它们。 您将了解模式如此重要的原因,并了解何时以及如何应用模式中的每一个。 在这里查看 !

目录

1.观察者模式 2.什么是观察者模式 3.实施观察者模式 4. Java内置的观察者模式 5.何时使用观察者模式 6.下载源代码

1.观察者模式

体育大厅是运动爱好者的理想运动场所。 它们涵盖几乎所有类型的体育活动,并提供最新新闻,信息,比赛预定日期,有关特定球员或球队的信息。 现在,他们计划提供实时评论或比赛分数作为SMS服务,但仅针对其高级用户。 他们的目标是在短时间间隔后发送即时比分,比赛情况和重要事件的短信。 作为用户,您需要订阅该程序包,并且在进行实时比赛时,您会收到有关实时评论的短信。 该站点还提供了一个随时取消订阅包的选项。

作为开发人员,运动大厅要求您为他们提供此新功能。 体育大厅的记者将坐在比赛的评论框中,并将实时评论更新为评论对象。 作为开发人员,您的工作是通过从评论对象(如果有)中获取评论来向注册用户提供评论。 进行更新时,系统应通过向订阅的用户发送SMS来更新他们。

这种情况清楚地显示了匹配项和用户之间的一对多映射,因为可能有许多用户订阅单个匹配项。 观察者设计模式最适合这种情况,让我们了解一下这种模式,然后为Sport Lobby创建功能。

2.什么是观察者模式

观察者模式是一种行为模式,与对象之间的职责分配有关。 行为模式表征了复杂的控制流,这些流在运行时很难遵循。 它们使您的注意力从控制流上移开,使您可以专注于对象的互连方式。

观察者模式定义了对象之间的一对多依赖关系,因此当一个对象改变状态时,其所有依赖关系都会得到通知并自动更新。 观察者模式描述了这些依赖关系。 此模式中的关键对象是主题和观察者。 主题可以具有任意数量的从属观察者。 只要对象的状态发生变化,就会通知所有观察者。 作为响应,每个观察者将查询主题以使其状态与主题状态同步。

了解观察者模式的另一种方法是发布者与订阅者之间的关系。 例如,假设您订阅了自己喜欢的体育或时尚杂志的杂志。 每当发行新期刊时,它就会交付给您。 如果您在不再需要该杂志时退订它,则该杂志将不会发送给您。 但是出版商继续像以前一样工作,因为还有其他人也订阅了该杂志。

类图1

图1

观察者模式有四个参与者:

  1. 主题,用于注册观察者。 对象使用此接口注册为观察者,也将自己从观察者中删除。
  2. 观察者,定义了一个对象的更新接口,该对象应该在主题更改时得到通知。 所有观察者都需要实现Observer接口。 此接口具有update()方法,当Subject的状态更改时将调用该方法。
  3. ConcreteSubject,将感兴趣的状态存储到ConcreteObserver对象。 状态更改时,它将向其观察者发送通知。 具体主题始终实现Subject接口。 每当状态更改时, notifyObservers()方法用于更新所有当前观察者。
  4. ConcreateObserver,维护对ConcreteSubject对象的引用,并实现Observer接口。 每个观察者都向具体主题注册以接收更新。

3.实施观察者模式

让我们看看如何在开发运动大厅功能时使用观察者模式。 有人将更新具体主题的对象,而您的工作是更新在具体主题对象中注册的对象的状态。 因此,只要具体主体对象的状态发生变化,就应该通知其所有依赖对象,然后进行更新。

类图2

图2

基于此,我们首先创建一个Subject接口。 在“主题”界面中,有三种主要方法,可以根据需要选择添加其他一些方法(如果需要)。

package com.javacodegeeks.patterns.observerpattern;public interface Subject {public void subscribeObserver(Observer observer);public void unSubscribeObserver(Observer observer);public void notifyObservers();public String subjectDetails();
}

Subject界面中的三个关键方法是:

  1. subscribeObserver ,用于订阅观察者,或者我们可以说注册观察者,以便如果主题状态发生变化,则应通知所有这些观察者。
  2. unSubscribeObserver ,用于取消订阅观察者,以便如果主题的状态发生变化,则不应通知此未订阅的观察者。
  3. notifyObservers ,当主题状态发生变化时,此方法通知注册的观察者。

并且可选地,还有一个方法subjectDetails() ,这是一个简单的方法,并且可以根据您的需要。 在这里,其工作是返回主题的详细信息。

现在,让我们看看Observer界面。

package com.javacodegeeks.patterns.observerpattern;public interface Observer {public void update(String desc);public void subscribe();public void unSubscribe();
}
  1. 当主题状态发生变化时,主题会在观察者上调用update(String desc)方法,以通知该方法。
  2. subscribe()方法用于订阅主题。
  3. unsubscribe() ,方法用于取消订阅主题。
package com.javacodegeeks.patterns.observerpattern;public interface Commentary {public void setDesc(String desc);
}

报告者使用以上接口来更新评论对象的实时评论。 这是一个可选接口,仅用于遵循代码与接口的原则 ,与Observer模式无关。 您应该在适用的情况下应用oops原则以及设计模式。 该界面仅包含一种用于更改具体主题对象状态的方法。

package com.javacodegeeks.patterns.observerpattern;import java.util.List;public class CommentaryObject implements Subject,Commentary{private final List<Observer>observers;private String desc;private final String subjectDetails;public CommentaryObject(List<Observer>observers,String subjectDetails){this.observers = observers;this.subjectDetails = subjectDetails;}@Overridepublic void subscribeObserver(Observer observer) {observers.add(observer);}@Overridepublic void unSubscribeObserver(Observer observer) {int index = observers.indexOf(observer);observers.remove(index);}@Overridepublic void notifyObservers() {System.out.println();for(Observer observer : observers){observer.update(desc);}}@Overridepublic void setDesc(String desc) {this.desc = desc;notifyObservers();}@Overridepublic String subjectDetails() {return subjectDetails;}}

上面的类作为一个具体的主题,它实现Subject接口并提供其实现。 它还将引用存储到已注册的观察者。

package com.javacodegeeks.patterns.observerpattern;public class SMSUsers implements Observer{private final Subject subject;private String desc;private String userInfo;public SMSUsers(Subject subject,String userInfo){if(subject==null){throw new IllegalArgumentException("No Publisher found.");}this.subject = subject;this.userInfo = userInfo;}@Overridepublic void update(String desc) {this.desc = desc;display();}private void display(){System.out.println("["+userInfo+"]: "+desc);}@Overridepublic void subscribe() {System.out.println("Subscribing "+userInfo+" to "+subject.subjectDetails()+" ...");this.subject.subscribeObserver(this);System.out.println("Subscribed successfully.");}@Overridepublic void unSubscribe() {System.out.println("Unsubscribing "+userInfo+" to "+subject.subjectDetails()+" ...");this.subject.unSubscribeObserver(this);System.out.println("Unsubscribed successfully.");}}

上面的类是实现Observer接口的具体观察者类。 它还存储对它订阅的主题的引用以及可选的用于显示用户信息的userInfo变量。

现在,让我们测试示例。

package com.javacodegeeks.patterns.observerpattern;import java.util.ArrayList;public class TestObserver {public static void main(String[] args) {Subject subject = new CommentaryObject(new ArrayList<Observer>(), "Soccer Match [2014AUG24]");Observer observer = new SMSUsers(subject, "Adam Warner [New York]");observer.subscribe();System.out.println();Observer observer2 = new SMSUsers(subject, "Tim Ronney [London]");observer2.subscribe();Commentary cObject = ((Commentary)subject);cObject.setDesc("Welcome to live Soccer match");cObject.setDesc("Current score 0-0");System.out.println();observer2.unSubscribe();System.out.println();cObject.setDesc("It's a goal!!");cObject.setDesc("Current score 1-0");System.out.println();Observer observer3 = new SMSUsers(subject, "Marrie [Paris]");observer3.subscribe();System.out.println();cObject.setDesc("It's another goal!!");cObject.setDesc("Half-time score 2-0");}}

上面的示例将产生以下输出:

Subscribing Adam Warner [New York] to Soccer Match [2014AUG24] ...
Subscribed successfully.Subscribing Tim Ronney [London] to Soccer Match [2014AUG24] ...
Subscribed successfully.[Adam Warner [New York]]: Welcome to live Soccer match
[Tim Ronney [London]]: Welcome to live Soccer match[Adam Warner [New York]]: Current score 0-0
[Tim Ronney [London]]: Current score 0-0Unsubscribing Tim Ronney [London] to Soccer Match [2014AUG24] ...
Unsubscribed successfully.[Adam Warner [New York]]: It's a goal!![Adam Warner [New York]]: Current score 1-0Subscribing Marrie [Paris] to Soccer Match [2014AUG24] ...
Subscribed successfully.[Adam Warner [New York]]: It's another goal!!
[Marrie [Paris]]: It's another goal!![Adam Warner [New York]]: Half-time score 2-0
[Marrie [Paris]]: Half-time score 2-0

如您所见,起初有两个用户订阅了足球比赛并开始接收评论。 但是后来有一个用户取消了订阅,因此该用户没有再收到评论。 然后,另一个用户订阅并开始获取评论。

所有这一切都是动态发生的,无需更改现有代码,不仅如此,假设该公司是否要在电子邮件上广播评论,或者任何其他公司希望与该公司合作以广播评论。 您需要做的就是创建两个新类,例如UserEmailColCompany并通过实现Observer接口使它们成为主题的Observer 。 据Subject知道它是观察者,它将提供更新。

4. Java内置的观察者模式

Java内置了对Observer模式的支持。 最通用的是java.util包中的Observer接口和Observable类。 这些与我们的“主题和观察者”界面非常相似,但是为您提供了许多现成的功能。

让我们尝试使用Java的内置Observer模式实现上述示例。

package com.javacodegeeks.patterns.observerpattern;import java.util.Observable;public class CommentaryObjectObservable extends Observable implements Commentary {private String desc;private final String subjectDetails;public CommentaryObjectObservable(String subjectDetails){this.subjectDetails = subjectDetails;}@Overridepublic void setDesc(String desc) {this.desc = desc;setChanged();notifyObservers(desc);}public String subjectDetails() {return subjectDetails;}
}

这次,我们扩展了Observable类,使我们的类成为一个主体,请注意,上面的类不包含对观察者的任何引用,它由父类处理,即Observable类。 但是,我们声明了setDesc方法来更改对象的状态,如上例所示。 setChanged方法是上层类的方法,用于将更改的标志设置为true。 notifyObservers方法通知其所有观察者,然后调用clearChanged方法以指示此对象不再更改。 每个观察者都有使用两个参数调用的update方法:一个observable对象和arg参数。

package com.javacodegeeks.patterns.observerpattern;import java.util.Observable;public class SMSUsersObserver implements java.util.Observer{private String desc;private final String userInfo;private final Observable observable;public SMSUsersObserver(Observable observable,String userInfo){this.observable = observable;this.userInfo = userInfo;}public void subscribe() {System.out.println("Subscribing "+userInfo+" to "+((CommentaryObjectObservable)(observable)).subjectDetails()+" ...");this.observable.addObserver(this);System.out.println("Subscribed successfully.");}public void unSubscribe() {System.out.println("Unsubscribing "+userInfo+" to "+((CommentaryObjectObservable)(observable)).subjectDetails()+" ...");this.observable.deleteObserver(this);System.out.println("Unsubscribed successfully.");}@Overridepublic void update(Observable o, Object arg) {desc = (String)arg;display();}private void display(){System.out.println("["+userInfo+"]: "+desc);}}

让我们讨论一些关键方法。

上面的类实现了Observer接口,该接口具有一个关键方法update ,当主题调用notifyObservers方法时会调用该方法。 update方法采用一个Observable对象和一个arg作为参数。

addObserver方法用于将观察者注册到主题,而deleteObserver方法用于将观察者从主题列表中删除。

让我们测试一下这个例子。

package com.javacodegeeks.patterns.observerpattern;public class Test {public static void main(String[] args) {CommentaryObjectObservable obj = new CommentaryObjectObservable("Soccer Match [2014AUG24]");SMSUsersObserver observer = new SMSUsersObserver(obj, "Adam Warner [New York]");SMSUsersObserver observer2 = new SMSUsersObserver(obj,"Tim Ronney [London]");observer.subscribe();observer2.subscribe();System.out.println("------------------------------------------------------");obj.setDesc("Welcome to live Soccer match");obj.setDesc("Current score 0-0");observer.unSubscribe();obj.setDesc("It's a goal!!");obj.setDesc("Current score 1-0");}
}

上面的示例将产生以下输出:

Subscribing Adam Warner [New York] to Soccer Match [2014AUG24] ...
Subscribed successfully.
Subscribing Tim Ronney [London] to Soccer Match [2014AUG24] ...
Subscribed successfully.
------------------------------------------------------
[Tim Ronney [London]]: Welcome to live Soccer match
[Adam Warner [New York]]: Welcome to live Soccer match
[Tim Ronney [London]]: Current score 0-0
[Adam Warner [New York]]: Current score 0-0
Unsubscribing Adam Warner [New York] to Soccer Match [2014AUG24] ...
Unsubscribed successfully.
[Tim Ronney [London]]: It's a goal!!
[Tim Ronney [London]]: Current score 1-0

上面的类创建一个主题和两个观察者。 observersubscribe方法将自己添加到主题观察者列表中。 然后setDesc更改主题的状态,该主题调用setChanged方法将更改标志设置为true,并通知观察者。 结果,调用了观察者的update方法,该方法在内部对display方法进行分类以显示结果。 后来,一位观察者unsubscribe d,即从观察者列表中将其删除。 由于此原因,以后的评论未更新。

Java为观察者模式提供了内置功能,但是它也有其自身的缺点。 Observable是一个类,您必须对其进行子类化。 这意味着您不能将Observable行为添加到已经扩展了另一个超类的现有类上。 这限制了重用潜力。 您甚至无法创建自己的实现,以与Java的内置Observer API配合使用。 Observable API中的某些方法受到保护。 这意味着除非已将Observable子类setChange否则无法调用setChange类的方法。 而且,您甚至无法创建Observable类的实例并将其与自己的对象组合在一起,因此必须子类化。 此设计违反了“优先继承而不是继承”的设计原则。

5.何时使用观察者模式

在以下任何一种情况下,请使用Observer模式:

  1. 当抽象具有两个方面时,一个方面依赖于另一个方面。 将这些方面封装在单独的对象中,可以使您分别进行更改和重用。
  2. 当更改一个对象需要更改其他对象时,您不知道需要更改多少个对象。
  3. 一个对象何时应该能够通知其他对象而无需假设这些对象是谁。 换句话说,您不希望这些对象紧密耦合。

6.下载源代码

这是“观察者模式”的一课。 您可以在此处下载源代码: ObserverPattern –第7课

翻译自: https://www.javacodegeeks.com/2015/09/observer-design-pattern.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/356917.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

震惊!2021年数十个技术领域图谱曝光,包含Golang、区块链、人工智能、架构师等领域学习路线

前言:不知道你是否和我一样,刚开始学习某个技术领域的时候缺乏坚持的动力,没有一个清晰的学习路线,学习的过程中没有人指导,遇到问题没人一起解答,想深入学习某个领域而又无从下手,不知道该从何处学起?这不,你想要的技术图谱来啦。有了这款武功秘籍,不光能开阔视野,…

70多套java必练项目,适合小白上手!

导读&#xff1a;这些项目不管是找工作练手&#xff0c;还是公司使用当作模板进一步改进&#xff0c;亦或者是当作毕业设计&#xff0c;都很有借鉴意义&#xff01; 编译器建议使用&#xff1a;IDEA,Myeclipse,eclipse,HB-X等都可以。 数据库建议使用&#xff0c;mysql,oracle,…

mysql mycat 路由规则_Mycat分库路由规则

Mycat分库路由规则发布时间&#xff1a;2020-06-15 16:54:10来源&#xff1a;51CTO阅读&#xff1a;11651作者&#xff1a;lzf05303774一、Mycat分库路由分为连续路由和离散路由。1、连续路由&#xff1a;(1)、常用的路由方式&#xff1a;auto-sharding-long、sharding-by-date…

孙叫兽CSDN社区云----WebIT已创建,欢迎大家前端全栈小伙伴踊跃加入

目录 社区云是什么&#xff1f; 创建CSDN社区云WebIT的目的 推荐分享的技术点&#xff08;如下图所示&#xff09; 社区成员权益 版主权益 管理员权益 WebIT社区云积分规则 WebIT优质版主及管理员可以申请直播分享前端技术 WebIT社区云将为社区运营者提供&#xff1a; …

迭代器设计模式示例

本文是我们名为“ Java设计模式 ”的学院课程的一部分。 在本课程中&#xff0c;您将深入研究大量的设计模式&#xff0c;并了解如何在Java中实现和利用它们。 您将了解模式如此重要的原因&#xff0c;并了解何时以及如何应用模式中的每一个。 在这里查看 &#xff01; 目录 …

uibinder表单提交_使用UIBinder的GWT自定义按钮

uibinder表单提交这是一个有关如何在GWT上使用UIBinder创建自定义按钮的示例。 public class GwtUIBinderButton implements EntryPoint {public void onModuleLoad() {Button button new Button();button.setText("Button");button.addClickHandler(new ClickHandl…

python用import xlwt出现红字_如何用python处理excel

最近看到有很多的python课程是教人怎么用python处理excel,我看了一下价格收费还贼高...这么初级毫无水平的操作我的粉丝们就不要花钱去报课程了..我免费教你们怎么做.首先我们先要安装两个模块,一个叫做xlrd,一个是xlwt.安装如下:打开cmd输入pip install xlrd等待安装成功,成功…

什么是升职率?

我确实相信您熟悉彼得原则 。 一般而言&#xff0c;该原则是一种观察&#xff0c;即晋升可能并且将导致晋升人员不再符合该职位的条件。 对于JVM&#xff0c;存在类似的问题。 太快地提升对象可能会对性能产生重大影响。 在这篇文章中&#xff0c;我们将探讨提升率的概念&…

mysql自增id用完了_MySQL表自增id用完了该怎么办?

我们知道MySQL表可以定义一个自增长的id&#xff0c;如果我们的表没有指定主键字段&#xff0c;那MySQL会给我们的表创建一个不可见的&#xff0c;长度为6个自己的row_id&#xff0c;然后不停地往上加步长&#xff0c;虽然生活中自然数是没有上限的&#xff0c;但是在计算机里&…

jmeter插件监控cpu小节点

JMeter使用plugins插件进行服务器性能监控 性能测试时&#xff0c;我们的关注点有两部分 1 服务本身&#xff1a;并发响应时间 QPS 2 服务器的资源使用情况&#xff1a;cpu memory I/O disk等 JMeter的plugins插件可以实现对"二"的监控&#xff0c;具体操作步骤如下(…

mysql写入监控_zabbix监控mysql操作

说明&#xff1a;配置zabbix自带Mysql模板# 创建目录mkdir /var/lib/zabbix# 创建连接数据库文件touch /var/lib/zabbix/.my.cnf# 写入数据连接信息[client]host 192.168.0.148user rootpassword 123dffsdfs# 创建监控项文件touch /etc/zabbix/zabbix_agentd.conf.d/userpar…

openshift_云上的播放框架变得简单:Openshift模块

openshift仅仅几年前&#xff0c;找到一个负担得起的Java Web应用程序托管解决方案是一项艰巨的任务&#xff0c;而寻找免费的托管解决方案是一项不可能的任务。 更不用说考虑自动缩放&#xff0c;单命令部署&#xff0c;持续集成等问题了&#xff0c;这简直就是科幻小说。 去年…

xclock 不出来界面_macOS 使用 XQuartz 支持 X11 实现 Linux 图形化界面显示

更多奇技淫巧欢迎订阅博客&#xff1a;https://fuckcloudnative.io前言在 Windows 中相信大家已经很熟悉使用 Xmanager(Xshell), MobaXterm, SecureCRT 通过 X11 实现 Linux 图形化界面显示&#xff0c;我的需求是在 macOS 下使用 iTerm2 作为 Terminal 实现 X11 图形化界面显示…

命令设计模式示例

本文是我们名为“ Java设计模式 ”的学院课程的一部分。 在本课程中&#xff0c;您将深入研究大量的设计模式&#xff0c;并了解如何在Java中实现和利用它们。 您将了解模式如此重要的原因&#xff0c;并了解何时以及如何应用模式中的每一个。 在这里查看 &#xff01; 目录 …

ArcGIS API for Silverlight 调用GP服务准备---GP模型建立、发布、测试

ArcGIS API for Silverlight 调用GP服务准备---GP模型建立、发布、测试 原文:ArcGIS API for Silverlight 调用GP服务准备---GP模型建立、发布、测试第一篇、GP降雨量等值线建模、发布及测试在水利、气象等行业中&#xff0c;要在WebGIS中实现空间分析功能&#xff0c;如绘制等…

win10企业版更新和安全中没有 “恢复”这个选项_通知:微软已强制对Windows 10更新升级...

最近&#xff0c;微软发布了Windows10的强制升级。从本月开始&#xff0c;如果您的个人电脑、笔记本电脑和其他设备没有手动升级&#xff0c;微软将强制部分用户升级到Windows10 1909或2004版本。原因很简单。微软已经停止支持Windows10 1903版&#xff08;包括家庭版和专业版&…

docker 多个mysql_mysql8.0 利用docker容器安装配置多主多从集群

1. 在/user/local/share/下创建mysql文件夹&#xff0c;在mysql文件夹目录下创建4个文件夹分别是:master1, master2, slave1, slave2分别在每个目录下建立data, conf, logs用于数据持久化创建后如下2.创建容器&#xff1a;1)创建一个名为master1的mysql容器(主 mysql)docker ru…

JavaFX 2.0和Scala,例如牛奶和饼干

JavaFX 2.0和Scala都是很好的技术&#xff0c;但是一起使用时效果会更好。 JavaFX 2.0是一种功能强大的富客户端技术&#xff0c;具有先进的图形&#xff0c;动画和媒体功能。 Scala是一种简单但功能强大的语言&#xff0c;具有用于编写特定于域的语言&#xff08;DSL&#xff…

thinkphp+mysql+join+where_thinkphp5.0 多join时where无法between

情况类似于这个链接,这帖子的老哥没有答案,现在遇到一样的问题了,下面贴上代码$map [products.insurance_status>1];//是否计算下线的产品if( input(get.times) && input(get.times) < 7 ){$time return_times(input(get.times));//此处有bug$map[order.pay_ti…

访客设计模式示例

本文是我们名为“ Java设计模式 ”的学院课程的一部分。 在本课程中&#xff0c;您将深入研究大量的设计模式&#xff0c;并了解如何在Java中实现和利用它们。 您将了解模式如此重要的原因&#xff0c;并了解何时以及如何应用模式中的每一个。 在这里查看 &#xff01; 目录 …