设计模式之观察者模式

在下载模块中经常要用到的一个模式就是观察者模式了,这是为了提高用户体验所决定的。

但用户在下载页面点击了下载之后,肯定希望除了这个下载页面能看到下载进度之外还能在其他地方看到,如通知栏等地方。

这时我们需要把下载任务进度实时更新到各个组件或者页面,如下载详情页,应用页,通知栏等地方。

实时更新下载进度有多种方法,

1、使用广播,在每次更新进度的时候发广播,当时比较耗电

2、使用handler,在要更新进度的时候发送message

3、使用观察者模式,注册观察者,在更新进度的时候提醒每个观察者。

当然,其中handler是可以结合起来使用的,因为handler可是实现线程间通信。

使用观察者模式能够较为便捷的通知组件更新进度,那么改怎么使用它呢?

  • 首先一个存储信息的DownloadInfo类,代码如下:

     public class DownloadInfo {
         
         private int progress;
     
         public int getProgress() {
             return progress;
         }
     
         public void setProgress(int progress) {
             this.progress = progress;
         }
     
     }
    

这个类并不复杂,主要是存储和取出下载信息

  • 其次要创建观察者接口,也就是观察者想要得到哪些信息,在这里,观察者要得到的信息是下载状态,观察者接口代码如下:

     public interface DownloadObserver {
     
         // 下载进度发生变化
         public void onDownloadProgressChanged(int progress);
     }
    
  • 第三步是要注册和注销观察者,注册即哪个组件需要得到进度发生改变的信息,注销即这一个观察者不在得到改变的信息。当然得到观察者对象我们要将其保存到一个集合之中,这时我们才能用for循环统一的通知观察者,代码如下:

     public class DownLoadTask {
         private DownloadInfo info;
     
         public DownLoadTask(DownloadInfo info) {
             this.info = info;
         }
     
         private ArrayList<DownloadObserver> observers = new ArrayList<>();
     
         public void registerObserver(DownloadObserver Observer) {
             if (Observer != null) {
                 observers.add(Observer);
             }
         }
     
         public void unregisterObserver(DownloadObserver Observer) {
             if (Observer != null) {
                 observers.remove(Observer);
             }
         }
     
         public void notifyAllObserver() {
             if (observers != null) {
                 for (Iterator<DownloadObserver> iterator = observers.iterator(); iterator.hasNext();) {
                     DownloadObserver observer = iterator.next();
                     observer.onDownloadProgressChanged(info.getProgress());
                 }
             }
         }
     
     }
    

在上面,我们将观察者对象存到ArrayList集合中,然后在notifyAllObserver()通过遍历的方式通知所有的观察者对象,这时就能让所有的观察者获得进度改变的信息

这样一来,我们的观察者的工具类已经准备好了,只需要我们调用registerObserver()注册好观察者,观察者就会添加进观察者的集合mObservers中,当有了观察者的数据之后,想获取通知就调用notifyDownloadStateChanged()或者notifyDownloadProgressChanged(),这两个方法就将信息传给了DownloadObserver观察者对象中。

然后调用的时候我们仅仅是获取了更新的数据,但是我们并不知道要更新哪一个控件,这就需要一个具体的观察者来实现了。

我们创建了三个简单的实现类,当获得进度更新的时候就输出进度到控制台上,代码如下:

实现类1:

public class DeskShow implements DownloadObserver{

    @Override
    public void onDownloadProgressChanged(int progress) {
        System.out.println("桌面显示进度: " + progress);
    }

}

实现类2:

public class NotionShow implements DownloadObserver{

    @Override
    public void onDownloadProgressChanged(int progress) {
        System.out.println("通知栏显示进度 :  " + progress);
    }

}

一切准备好之后,就可以在主方法中使用它们了,主方法代码如下:

public class Download {

    public static void main(String[] args) {
        // 创建三个观察者对象
        DeskShow deskShow = new DeskShow();
        NotionShow notionShow = new NotionShow();
        OtherShow otherShow = new OtherShow();
        
        DownloadInfo info = new DownloadInfo();
        DownLoadTask downLoadTask = new DownLoadTask(info);
        // 注册观察者对象到集合中
        downLoadTask.registerObserver(deskShow);
        downLoadTask.registerObserver(notionShow);
        downLoadTask.registerObserver(otherShow);

        new Thread() {
            public void run() {
                int progress = 0;
                while (true) {
                    try {
                        sleep(500);
                    } catch (InterruptedException e) {                            
                        e.printStackTrace();
                    }
                    // 每隔0.5秒更改一次DownloadInfo的信息
                    progress = progress + 1;
                    info.setProgress(progress);
                    // 更改信息之后通知观察者
                    downLoadTask.notifyAllObserver();
                }

            };
        }.start();

    }

}

这样整个观察者的模型就已经完成了,在外部传入DownloadInfo的进度值之后,直接调用downLoadTask的notifyAllObserver(),就可以通知所有的观察者当前的进度。

探究观察者模式的本质,就是java中回调的使用方式,获得具体的信息,把不确定的信息设置为一个方法,归由子类实现。

总结

或许大家看完这个模型,对于观察者模式还有一点疑惑,那么我们来总结一下使用观察者模式的步骤吧!

1、创建一个类,这个类是用于保存动态的需要改变的数据(被观察者),在本文表示DownloadInfo类;

2、创建一个接口类,这个类用于观察对象状态的改变(观察者),在本文表示DownloadObserver类;

3、创建一个注册和注销观察者的任务类(DownLoadTask),这个类拥有注册和注销观察者,并且在被观察这信息发送改变时通知所有的观察者。

4、实现DownloadObserver类,这些实现类实现接收到DownloadInfo类信息发生改变的时候要实现的功能,在本文即是DeskShow类,输出进度语句。

这样一个观察者的模型就组件好了!

最后就是在主方法中注册观察者,然后传入改变的数据,通知所有的观察者。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 210,835评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 89,900评论 2 383
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,481评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,303评论 1 282
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,375评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,729评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,877评论 3 404
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,633评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,088评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,443评论 2 326
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,563评论 1 339
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,251评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,827评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,712评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,943评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,240评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,435评论 2 348

推荐阅读更多精彩内容

  • 客户需求 程序设计 一个气象站对应着多个客户端,气象站的数据一发生变化,客户端的数据也要随着更新,这就形成了一种依...
    BlainPeng阅读 992评论 1 17
  • 介绍 定义:观察者模式(Observer)有时又被称为发布/订阅模式,当一个对象状态发生改变时,依赖它的对象全部会...
    四月不见阅读 364评论 0 0
  • 观察者模式 Rxjava中运用到了观察者模式,那什么是观察者模式呢,现在来学习一下。正所谓观察,就是看,细察事物的...
    cgzysan阅读 547评论 0 4
  • 前言定义:观察者设计模式定义了对象间的一种一对多的依赖关系,以便一个对象的状态发生变化时,所有依赖于它的对象都得到...
    xsp单细胞阅读 449评论 0 1
  • 观察者模式 有时,我们希望在一个对象的状态改变时更新另外一组对象。在MVC模式中有这样一个非常常见的例子,假设在两...
    英武阅读 4,172评论 0 51