設(shè)計(jì)模式之觀察者模式

在下載模塊中經(jīng)常要用到的一個(gè)模式就是觀察者模式了,這是為了提高用戶體驗(yàn)所決定的。

但用戶在下載頁(yè)面點(diǎn)擊了下載之后,肯定希望除了這個(gè)下載頁(yè)面能看到下載進(jìn)度之外還能在其他地方看到,如通知欄等地方。

這時(shí)我們需要把下載任務(wù)進(jìn)度實(shí)時(shí)更新到各個(gè)組件或者頁(yè)面,如下載詳情頁(yè),應(yīng)用頁(yè),通知欄等地方。

實(shí)時(shí)更新下載進(jìn)度有多種方法,

1、使用廣播,在每次更新進(jìn)度的時(shí)候發(fā)廣播,當(dāng)時(shí)比較耗電

2、使用handler,在要更新進(jìn)度的時(shí)候發(fā)送message

3、使用觀察者模式,注冊(cè)觀察者,在更新進(jìn)度的時(shí)候提醒每個(gè)觀察者。

當(dāng)然,其中handler是可以結(jié)合起來(lái)使用的,因?yàn)閔andler可是實(shí)現(xiàn)線程間通信。

使用觀察者模式能夠較為便捷的通知組件更新進(jìn)度,那么改怎么使用它呢?

  • 首先一個(gè)存儲(chǔ)信息的DownloadInfo類,代碼如下:

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

這個(gè)類并不復(fù)雜,主要是存儲(chǔ)和取出下載信息

  • 其次要?jiǎng)?chuàng)建觀察者接口,也就是觀察者想要得到哪些信息,在這里,觀察者要得到的信息是下載狀態(tài),觀察者接口代碼如下:

     public interface DownloadObserver {
     
         // 下載進(jìn)度發(fā)生變化
         public void onDownloadProgressChanged(int progress);
     }
    
  • 第三步是要注冊(cè)和注銷觀察者,注冊(cè)即哪個(gè)組件需要得到進(jìn)度發(fā)生改變的信息,注銷即這一個(gè)觀察者不在得到改變的信息。當(dāng)然得到觀察者對(duì)象我們要將其保存到一個(gè)集合之中,這時(shí)我們才能用for循環(huán)統(tǒng)一的通知觀察者,代碼如下:

     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());
                 }
             }
         }
     
     }
    

在上面,我們將觀察者對(duì)象存到ArrayList集合中,然后在notifyAllObserver()通過(guò)遍歷的方式通知所有的觀察者對(duì)象,這時(shí)就能讓所有的觀察者獲得進(jìn)度改變的信息

這樣一來(lái),我們的觀察者的工具類已經(jīng)準(zhǔn)備好了,只需要我們調(diào)用registerObserver()注冊(cè)好觀察者,觀察者就會(huì)添加進(jìn)觀察者的集合mObservers中,當(dāng)有了觀察者的數(shù)據(jù)之后,想獲取通知就調(diào)用notifyDownloadStateChanged()或者notifyDownloadProgressChanged(),這兩個(gè)方法就將信息傳給了DownloadObserver觀察者對(duì)象中。

然后調(diào)用的時(shí)候我們僅僅是獲取了更新的數(shù)據(jù),但是我們并不知道要更新哪一個(gè)控件,這就需要一個(gè)具體的觀察者來(lái)實(shí)現(xiàn)了。

我們創(chuàng)建了三個(gè)簡(jiǎn)單的實(shí)現(xiàn)類,當(dāng)獲得進(jìn)度更新的時(shí)候就輸出進(jìn)度到控制臺(tái)上,代碼如下:

實(shí)現(xiàn)類1:

public class DeskShow implements DownloadObserver{

    @Override
    public void onDownloadProgressChanged(int progress) {
        System.out.println("桌面顯示進(jìn)度: " + progress);
    }

}

實(shí)現(xiàn)類2:

public class NotionShow implements DownloadObserver{

    @Override
    public void onDownloadProgressChanged(int progress) {
        System.out.println("通知欄顯示進(jìn)度 :  " + progress);
    }

}

一切準(zhǔn)備好之后,就可以在主方法中使用它們了,主方法代碼如下:

public class Download {

    public static void main(String[] args) {
        // 創(chuàng)建三個(gè)觀察者對(duì)象
        DeskShow deskShow = new DeskShow();
        NotionShow notionShow = new NotionShow();
        OtherShow otherShow = new OtherShow();
        
        DownloadInfo info = new DownloadInfo();
        DownLoadTask downLoadTask = new DownLoadTask(info);
        // 注冊(cè)觀察者對(duì)象到集合中
        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();

    }

}

這樣整個(gè)觀察者的模型就已經(jīng)完成了,在外部傳入DownloadInfo的進(jìn)度值之后,直接調(diào)用downLoadTask的notifyAllObserver(),就可以通知所有的觀察者當(dāng)前的進(jìn)度。

探究觀察者模式的本質(zhì),就是java中回調(diào)的使用方式,獲得具體的信息,把不確定的信息設(shè)置為一個(gè)方法,歸由子類實(shí)現(xiàn)。

總結(jié)

或許大家看完這個(gè)模型,對(duì)于觀察者模式還有一點(diǎn)疑惑,那么我們來(lái)總結(jié)一下使用觀察者模式的步驟吧!

1、創(chuàng)建一個(gè)類,這個(gè)類是用于保存動(dòng)態(tài)的需要改變的數(shù)據(jù)(被觀察者),在本文表示DownloadInfo類;

2、創(chuàng)建一個(gè)接口類,這個(gè)類用于觀察對(duì)象狀態(tài)的改變(觀察者),在本文表示DownloadObserver類;

3、創(chuàng)建一個(gè)注冊(cè)和注銷觀察者的任務(wù)類(DownLoadTask),這個(gè)類擁有注冊(cè)和注銷觀察者,并且在被觀察這信息發(fā)送改變時(shí)通知所有的觀察者。

4、實(shí)現(xiàn)DownloadObserver類,這些實(shí)現(xiàn)類實(shí)現(xiàn)接收到DownloadInfo類信息發(fā)生改變的時(shí)候要實(shí)現(xiàn)的功能,在本文即是DeskShow類,輸出進(jìn)度語(yǔ)句。

這樣一個(gè)觀察者的模型就組件好了!

最后就是在主方法中注冊(cè)觀察者,然后傳入改變的數(shù)據(jù),通知所有的觀察者。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 客戶需求 程序設(shè)計(jì) 一個(gè)氣象站對(duì)應(yīng)著多個(gè)客戶端,氣象站的數(shù)據(jù)一發(fā)生變化,客戶端的數(shù)據(jù)也要隨著更新,這就形成了一種依...
    BlainPeng閱讀 1,120評(píng)論 1 17
  • 介紹 定義:觀察者模式(Observer)有時(shí)又被稱為發(fā)布/訂閱模式,當(dāng)一個(gè)對(duì)象狀態(tài)發(fā)生改變時(shí),依賴它的對(duì)象全部會(huì)...
    四月不見(jiàn)閱讀 445評(píng)論 0 0
  • 觀察者模式 Rxjava中運(yùn)用到了觀察者模式,那什么是觀察者模式呢,現(xiàn)在來(lái)學(xué)習(xí)一下。正所謂觀察,就是看,細(xì)察事物的...
    cgzysan閱讀 623評(píng)論 0 4
  • 前言定義:觀察者設(shè)計(jì)模式定義了對(duì)象間的一種一對(duì)多的依賴關(guān)系,以便一個(gè)對(duì)象的狀態(tài)發(fā)生變化時(shí),所有依賴于它的對(duì)象都得到...
    xsp單細(xì)胞閱讀 504評(píng)論 0 1
  • 觀察者模式 有時(shí),我們希望在一個(gè)對(duì)象的狀態(tài)改變時(shí)更新另外一組對(duì)象。在MVC模式中有這樣一個(gè)非常常見(jiàn)的例子,假設(shè)在兩...
    英武閱讀 4,314評(píng)論 0 51

友情鏈接更多精彩內(nèi)容