Java基础再回首之设计模式系列②-----Observer 观察者模式(案列教程,附带demo)
来源:互联网 发布:顶尖条码电子称软件 编辑:程序博客网 时间:2024/06/03 22:55
一、前言。
昨天我费尽心思了4个小时,终于把我的设计模式系列的第一篇开了新的大门,有意者可以看看哒。
传送门:Java基础再回首之设计模式系列①—–StrategyPattern 策略者模式(案列教程,附带demo)时间就像海绵,只要愿意挤,还是会有的。 ——-鲁迅
虽然身处工作的我,还是愿意挤出一点时间,充下电,今天给大家详细的图文并茂的分析 Observer 观察者模式,真的想一起学习哒~在博文下方留言,咱们一起学习,共勉设计模式带来的方便。
二、案列。
正是因为上篇文章的设计模式得到好评(哈哈~),又来了新的项目了,不过这次的项目要求有所不同。
1.为贵公司建立一个 新版本的电子杂志社的全新系统。 该电子杂志社必须建立JournalData对象中,由JournalData来负责追踪电子杂志社发来的各大新闻日报信息。
2.而且,该系统还是可以拓展的。可以作为API卖数据给第三方,这样可以建立良好的运营商业模式,一旦有客户上门,他们使用该服务数据都是需要收费的。
我们看看大概的思维导图:
1.JournalData对象作为一个中间站负责采集电子杂志社的各大新闻的信息。
2.只有订阅了对象系统的信息的客户,才可以收到对象系统的发来的公告。
3.各个客户各不知道彼此的信息订阅,如果某刻某个客户退出了订阅,不会影响到其他客户的订阅,而且其他客户也不知道,只有在对象系统中知道,而且从此之后,就不会再向该客户提供任何新闻信息。
三.代码实现。
我们看看代码架构:
这次我们不用普通方案,看了上面的要求。我开始先写3个接口:
①. ISubiect :分别作为 新增客户、移除客户、通知客户更新数据 ;
public interface ISubiect { //注册一个观察者 void registerObserver(IObserver iObserver); //移除一个观察者 void removeObserver(IObserver iObserver); //通知有数据更新啦 void notifyObserver(IObserver iObserver);}
②. IObject : 当有新闻信息更新时后,系统会把一些新闻数据去传递给所有观察者。
public interface IObserver { /** * * @param entertainmentNews 娱乐新闻 * @param militaryNews 军事新闻 * @param peopleNews 民生新闻 */ void update(String entertainmentNews,String militaryNews,String peopleNews);}
③.IDisplayElement:此接口仅仅只是所有观察者要展示用户观察者收到的数据。(可以不用写,此处只是打印出收到的数据)
public interface IDisplayElement { //所有的观察者要展示自己受到的新闻信息 void DisplayElement();}
④我们看看杂志系统的代码:
public class JournalData implements ISubject { //所有的观察者集合,并且泛型指向观察者接口 private List<IObserver> observer; //娱乐新闻 private String entertainmentNews; //军事新闻 private String militaryNews; //民生新闻 private String peopleNews; //构造方法就为集合实例化 public JournalData() { observer = new ArrayList(); } //注册一个观察者 @Override public void registerObserver(IObserver iObserver) { observer.add(iObserver); } //移除一个观察者 @Override public void removeObserver(IObserver iObserver) { int index = observer.indexOf(iObserver); if (observer.size() > 0) { observer.remove(index); } } //通知所有的观察者有数据更新啦 @Override public void notifyObserver() { for (IObserver temIObserver : observer) { temIObserver.update(entertainmentNews, militaryNews, peopleNews); } } //设置数据 public void setJourData(String entertainmentNews, String militaryNews, String peopleNews) { this.entertainmentNews = entertainmentNews; this.militaryNews = militaryNews; this.peopleNews = peopleNews; notifyObserver();//别忘了设置完数据,通知所有观察者有数据更新啦 }}
⑤ 看看我们的用户怎么做的:
public class User1 implements IObserver, IDisplayElement { //定义一个观察者管理的接口,方便以后可以移除操作 private ISubject iSubject; private String entertainmentNews; private String militaryNews; private String peopleNews; public User1(ISubject iSubject) { this.iSubject = iSubject; iSubject.registerObserver(this); } @Override public void update(String entertainmentNews, String militaryNews, String peopleNews) { this.entertainmentNews = entertainmentNews; this.militaryNews = militaryNews; this.peopleNews = peopleNews; DisplayElement(); } @Override public void DisplayElement() { System.out.print("用户一收到了娱乐新闻:" + entertainmentNews + ",军事新闻:" + militaryNews + ", 民生新闻:" + peopleNews); }}
⑥、启动杂志社。
public class Main { public static void main(String[] args) { JournalData journalData = new JournalData(); //此处我使用匿名对象注册观察者 new User1(journalData); new User2(journalData); //有数据过来了 journalData.setJourData("明星黄晓明孩子出世啦" , "美俄战机一周内黑海上空两度遭遇" , "广州市民幸福度80%"); }}
四、总结以上观察者模式。
要点:
1.定义了对象之间的一对多的关系。
2.出版者用一个共同的接口来更新观察者数据更新。
3.出版者和观察者之间用松耦合的方式结合,出版者不知道观察者的细节,只知道了观察者实现了接口。
问题来了:
如果存在观察者想要自己动身去出版社取数据,而不是统一让出版社发出数据。毕竟有时候出版社已经有数据了,只是未到时间、参数不齐等其他原因,未能立刻发出去,但是已经有数据了的。这就造成了观察者心急但是吃不了热豆腐啊。那如何让观察者“心急也能吃到热豆腐呢?”,能立刻吃到“热豆腐呢?”。
五、利用Java内置的观察者模式。
很高兴告诉你,Java API有内置的观察者模式,Java.util包内包括最基本的Observer接口和Obersver类,这个和我们上面的ISubject接口和IObersver接口非常相似,利用内置的观察者模式更方便解决我所引出上面的问题。其功能都已经实现好了的,你在此作为出版社可以把信息放着,等待着观察者来取。当然啦!你也可以直接一次性推送出去给观察者。这样,你就可以免了搭建框架,又可以随心所欲的让观察者“心急也能吃到热豆腐!”。
5.1 内置的观察者模式源码分析。(先上完代码,再一步一步分析。)
1.现在我们继承要写的杂志系统要继承的 java.util包的Observable类。
public class JournalData extends Observable { //娱乐新闻 private String entertainmentNews; //军事新闻 private String militaryNews; //民生新闻 private String peopleNews; //设置数据 public void setJourData(String entertainmentNews, String militaryNews, String peopleNews) { this.entertainmentNews = entertainmentNews; this.militaryNews = militaryNews; this.peopleNews = peopleNews; dataChanged(); } private void dataChanged() { setChanged(); notifyObservers(); } //就让取观察者自己来取“热豆腐”吧 public String getEntertainmentNews() { return entertainmentNews; } public String getMilitaryNews() { return militaryNews; } public String getPeopleNews() { return peopleNews; }}
2.看看我们的用户观察者类。
public class User1 implements Observer, Display { private Observable observable; //娱乐新闻 private String entertainmentNews; //军事新闻 private String militaryNews; //民生新闻 private String peopleNews; //注册一个订阅 public void addObserver(Observable observable) { this.observable = observable; observable.addObserver(this); } //删除一个订阅 public void deleteObserver(Observable observable) { observable.deleteObserver(this); } //删除所有订阅 public void deleteAllObserver() { observable.deleteObservers(); } @Override public void update(Observable observable, Object arg) { //先判断JournalData是否属于Observable的实例,如果存在多个Observable 子类,这行代码非常必要 if (observable instanceof JournalData) { //如果是,把实例向下转型为JournalData对象 JournalData journalData = (JournalData) observable; this.entertainmentNews = journalData.getEntertainmentNews(); this.militaryNews = journalData.getMilitaryNews(); this.peopleNews = journalData.getPeopleNews(); } } @Override public void Display() { System.out.print("用户一收到了娱乐新闻:" + entertainmentNews + ",军事新闻:" + militaryNews + ", 民生新闻:" + peopleNews); }}
5.3 分析。
1.现在我们的杂志社改为了继承了一个类Obersver,说明一下,这个类不是抽象类!而是一个和我们上面手写的JournalData.java一样。都是有接口集合,看看右边的这个类的方法,发现它还有统计订阅者的个数方法 countObservers()。看看下图:
2.JournalData.java类里面有setChanged()、hasChanged、clearChanged()方法,旨在表示状态已经发生改变,做一个开关,如果出版社想要发送出去就调用父类的 clearChanged()方法,如果只是想让观察者自己来获取数据就setChanged()。总的来说,这就是一个开关。
官方这样解释的:想让推送者有自己的监控,可以随自己的要求去推送或者不推送,可以避免了最近注册的观察者错过了最近发出的通知。
下面我抽出官方源码来看看:(注意只有 changed=true才会推送出去,也就是调用setChanged()方法。)
public void notifyObservers(Object arg) { Object[] arrLocal; synchronized (this) { if (!changed) return; arrLocal = obs.toArray(); clearChanged(); } for (int i = arrLocal.length-1; i>=0; i--) ((Observer)arrLocal[i]).update(this, arg); }
3.现在我们把眼光转到用户的update()方法,可以看到有两个参数Observable observable和Object arg,第一个参数observable之前注册自己的被观察者,第二个参数作为可以传递对象过来的参数,一般地,如果不加以传递参数过来,都是为null,可以不加理会。
六、内置的观察者模式总结:
1.使用内置的Java观察者模式,可以轻松的实现“推”和“拉”的方式。可以按照推送者的要求去推送自己想要的内容。
2.内置的观察者模式通知观察者的次序是不一样的,实现了松耦合。
3.内置的观察者模式的黑暗面:它使用的是一个类,而不是一个接口,这大大限制了它的使用和复用,这违背了“多用组合,少用继承”的原则。
4.不管怎么样,按照自己的需求,选择哪种方式!反正都熟悉了观察者模式了。
- Java基础再回首之设计模式系列②-----Observer 观察者模式(案列教程,附带demo)
- Java基础再回首之设计模式系列①-----StrategyPattern 策略者模式(案列教程,附带demo)
- Java设计模式之Observer(观察者)模式
- Java设计模式之Observer 观察者模式
- Java设计模式之Observer-观察者模式
- java设计模式之观察者模式Observer
- java设计模式之观察者模式Observer
- Java设计模式之Observer(观察者)模式
- java设计模式之观察者模式(observer)
- Java设计模式之观察者(Observer)模式
- Java 设计模式之观察者模式(Observer pattern)
- Java设计模式之观察者模式(Observer)
- Java设计模式之观察者模式(Observer)
- Java设计模式之观察者模式(Observer Pattern)
- 设计模式之Observer(观察者模式)
- 设计模式之Observer(观察者模式)
- 【设计模式】之观察者模式(Observer)
- 设计模式之--观察者模式(Observer)
- android camear2使用
- 苹果(再解01背包问题)
- 初学者开始Python之路的一个好网站
- C# 学习过程知识点累积
- TCP/IP网络编程_计算器服务器端客户端
- Java基础再回首之设计模式系列②-----Observer 观察者模式(案列教程,附带demo)
- php 自制时间格式化
- R数据分析实例:稳健回归
- fastjson和gson对json中数据类型和格式的兼容性对比
- linux uart编程
- android studio解决warning: Ignoring InnerClasses attribute for an anonymous inner class
- String类split方法的使用(字符串以'.'分隔得不到任何内容)
- <LeetCode>115.Distinct Subsequences 求相同子序列数 Tag:DP, string
- HDU 1875 畅通工程再续——最小生成树