1. 程式人生 > >使用觀察者模式實現執行緒將計算結果回撥給多個物件

使用觀察者模式實現執行緒將計算結果回撥給多個物件

《Java網路程式設計》第三章執行緒講使用回撥的方法從執行緒中返回資訊給物件。例如,如果有多個物件對執行緒的計算結果感興趣,那麼執行緒可以儲存一個要回調的物件列表。特定的物件可以通過呼叫執行緒類的一個方法把自己新增到這個列表中來完成註冊,表示自己對計算結果很感興趣。如果有多個類的例項對結果感興趣,可以定義一個新的Observer interface (介面),所有這些類都要實現這個新介面。這個Observer interface(介面)將宣告回撥方法。以上是觀察者模式的典型應用場景。

接下來將上面的需求實現。

1.       Observer介面

宣告回撥方法update

interface Observer {
    void update(byte[] digest);
}

2.       感興趣的觀察者InstanceCallbackDigestUserInterface01

其中將通知者作為其成員變數

public class InstanceCallbackDigestUserInterface01 implements Observer {

    static Logger logger = LoggerFactory.getLogger(InstanceCallbackDigestUserInterface01.class);

    private String filename;
    private byte[] digest;

    public InstanceCallbackDigestUserInterface01(String filename) {
        this.filename = filename;
    }

    @Override
    public String toString() {
        String result = filename + ": ";
        if (digest != null) {
            result += DatatypeConverter.printHexBinary(digest);
        } else {
            result += "digest not available";
        }
        return result;
    }

    @Override
    public void update(byte[] digest) {
        this.digest = digest;
        //只是顯示摘要,但功能更強的類還可以完成其他操作
        //如將摘要儲存在一個欄位中,用它啟動另一個錢程,或者對它完成進一步的計算。
        logger.info(this.toString());
    }
}

3.       感興趣的觀察者InstanceCallbackDigestUserInterface02以及新執行緒任務SaveDatabase

public class InstanceCallbackDigestUserInterface02 implements Observer {

    Logger logger = LoggerFactory.getLogger(InstanceCallbackDigestUserInterface02.class);

    byte[] digest = null;

    @Override
    public void update(byte[] digest) {
        logger.info("interface02 get this digest");
        this.digest = digest;
        ExecutorService exec = Executors.newCachedThreadPool();
        exec.submit(new SaveDatabase(digest));
    }
}

class SaveDatabase implements Runnable {

    Logger logger = LoggerFactory.getLogger(SaveDatabase.class);
    private byte[] digest;

    public SaveDatabase(byte[] digest){
        this.digest = digest;
    }

    @Override
    public void run() {
        String s = DatatypeConverter.printHexBinary(digest);
        logger.info(s);
    }
}

4.       通知者InstanceCallbackDigest


儲存一個要回調的物件列表callback。特定的物件可以通過呼叫attach方法把自己新增到這個列表中來完成註冊

public class InstanceCallbackDigest implements Runnable {

    Logger logger = LoggerFactory.getLogger(InstanceCallbackDigest.class);

    private String filename;
    private LinkedHashSet<Observer> callback = new LinkedHashSet<>();

    public InstanceCallbackDigest(String filename) {
        this.filename = filename;
    }

    public void attach(Observer observer) {
        callback.add(observer);
    }

    public void detach(Observer observer) {
        callback.remove(observer);
    }

    @Override
    public void run() {
        try {
            FileInputStream in = new FileInputStream(filename);
            MessageDigest sha = MessageDigest.getInstance("SHA-256");
            DigestInputStream din = new DigestInputStream(in, sha);
            while (din.read() != -1) ;  // read entire file
            din.close();
            byte[] digest = sha.digest();
            for (Observer o:callback
                 ) {
                logger.info("callback update");
                o.update(digest);
            }
        } catch (IOException | NoSuchAlgorithmException ex) {
            System.err.println(ex);
        }
    }
}

5.       Test類

public class Test {
    static Logger logger = LoggerFactory.getLogger(Test.class);

    public void calculateDigest(String filename, LinkedHashSet<Observer> callback) {
        InstanceCallbackDigest cb = new InstanceCallbackDigest(filename);
        //註冊
        for (Observer o : callback
                ) {
            cb.attach(o);
        }
        Thread t = new Thread(cb);
        t.start();
    }

    @org.junit.Test
    public void test () {
        logger.info("main執行緒");
        String[] strs = new String[]{"bw01.txt","pom.xml"};
//        String[] strs = new String[]{"bw01.txt"};
        for (String filename : strs) {
            //註冊
            InstanceCallbackDigestUserInterface01 d = new InstanceCallbackDigestUserInterface01(filename);
            InstanceCallbackDigestUserInterface02 interface02 = new
                    InstanceCallbackDigestUserInterface02();
            LinkedHashSet<Observer> callback = new LinkedHashSet<>();
            callback.add(d);
            callback.add(interface02);

            //啟動了執行緒
            calculateDigest(filename, callback);

            //如何通知主執行緒子執行緒結束?
            try {
                TimeUnit.SECONDS.sleep(3l);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

6.       類圖


7.       執行結果



相關推薦

使用觀察模式實現執行計算結果撥給物件

《Java網路程式設計》第三章執行緒講使用回撥的方法從執行緒中返回資訊給物件。例如,如果有多個物件對執行緒的計算結果感興趣,那麼執行緒可以儲存一個要回調的物件列表。特定的物件可以通過呼叫執行緒類的一個方法把自己新增到這個列表中來完成註冊,表示自己對計算結果很感興趣。如果有多

(實驗)Java一個執行用synchronized巢狀鎖物件時呼叫wait()只釋放wait函式關聯的所物件還是釋放所有鎖物件

實驗是在JDK1.8下做的。 題目起的比較拗口,其實用程式碼說明起來更簡單,如下所示: public class MultiSynchronizedTest { private static Object lock1 = new Object(); p

java和c++觀察模式實現

觀察者模式是一種比較常用的設計模式,,採用介面,封裝類中動態變化的方法,定義物件間的依賴關係,一邊但一個物件狀態發生改變時,所有以來他的物件都發生改變。 簡單的說,就是一管多,即關鍵就是觀察者和被觀察者,學習這一部分看其他部落格這樣解釋,就是多個屌絲追一個白富美的模式,多個屌絲就是所謂的觀察

觀察模式實現(模仿CSharpMessenger擴充套件)

我們在遊戲開發中經常會用到這種模式,用於模組之間的訊息分發,來降低模組之間耦合性,基本原來就是利用字串作為key值來儲存回撥函式(大多數觀察者模式使用字串作為訊息佇列中的key值),分發訊息時檢索key值來獲取回撥函式並執行來達到模組之間互動的功能,為了實現訊息型別拓展,這裡我使用了類模板來實現

觀察模式實現的 `釋出/訂閱` 模型

釋出者 package indi.lewis.pub; import java.util.Observable; import java.util.Observer; import java.uti

設計模式(二):自己動手使用“觀察模式實現通知機制

在之前釋出Objective-C系列部落格的時候,其中提到過OC的通知機制,請參考《Objective-C中的老闆是這樣發通知的(Notification)》這篇部落格。在之前關於Notification的部落格中,只介紹了Foundation框架中的通知的使用方式。正如前面部落格中提到的那樣,通知是“一對多

觀察模式實現案例(C++)

#include <iostream> #include <string> #include <vector> #include <memory> using namespace std; class Cat; //前置

es6觀察模式實現

//es6實現 藉助set實現 function obfunction(oldval,newval){ console.log(oldval+'變成了'+newval); } class targetObser{ constructor(age,name){ this

利用觀察模式實現Cocos2DX-lua遊戲中的訊息管理系統

http://blog.csdn.net/operhero1990/article/details/48575487                遊戲中某些物件往往需要及時獲知其他特定物件狀體的改變。為降低類之間的耦合度,可以建立訊息管理系統,實現訊息的集中與分發。觀察者

觀察模式實現老闆狀態變化通知 C++

說下對觀察者模式的理解: 觀察者模式定義了一種一對多的依賴關係, 讓多個觀察者物件可以同時監聽某一主題物件, 當這個主題物件的狀態發生改變的時候, 就會通知所有的觀察者物件, 使他們可以自動更新自己。

JAVA中實現執行相互呼叫或

使用場景: 在工作中,遇到同時兩個執行緒A和B,按照通常的理解,A呼叫B以後A繼續執行,但是在我目前的情況下需要B執行完畢以後才能繼續執行A後面的程式,於是有了此文章。 請看程式碼: 首先定義一個介面

使用BlockingQueue,執行同時處理同一型別的資源

如果是單執行緒處理一批事情,例如,有16個日誌需要處理,各個日誌之間是獨立的,假設處理每個的時間是1秒, 一共需要處理16秒才能處理完。 現在使用多執行緒來加速處理時間,思路: 建立4個執行緒,每個執行緒從一個任務列表中獲取一個任務,進行處理,處理完後,再獲取一個,直到任務

觀察模式執行執行訂閱事件並順序執行的問題

       對事件釋出訂閱模式中啟動執行緒執行操作,但又要保證執行緒順序執行的一些思考和實踐,在開發過程中,經常會遇到需要使用事件來觸發方法執行的情況,比如CS中按鈕的點選事件,滑鼠移動事件,鍵盤監聽事件等等,有時候需要執行比較耗時的任務,但並不希望阻塞主執

利用觀察模式來獲取執行中的資料或者調函式

首先//抽象主題角色,watched:被觀察 public interface Watched { public void addWatcher(Watcher watcher); public void removeWatcher(Watcher wat

執行安全的觀察模式的設計

觀察者模式的應用,主要的行為就是註冊和移除觀察者(observer),以及通知所有已註冊的Observers。這裡介紹的是Chromium專案中實現的執行緒安全的觀察者管理及通知的基礎類ObserverListThreadSafe, 它的能力包括: 觀察者可

觀察模式,無需執行完成資料監聽

大家好,我們今天來了解一個新的設計模式——觀察者模式。 觀察者模式的思路很簡單,它被廣泛地用在各種資料監控上。很多時候我們希望監聽某個資料的變化,希望一旦獲悉它的變化之後立即採取一些舉措。按照常規的操作,我們需要開啟額外的執行緒來進行監聽。但是開啟執行緒一則非常麻煩,二則需要帶來額外的開銷,我們今天介紹的觀察

設計模式——觀察模式(C++實現

ace mes des ret rtu cto pattern virt date 1 #include <iostream> 2 #include <vector> 3 #include <algorithm>

淺談java中內置的觀察模式與動態代理的實現

所有 代理 notify play ani effect 一個 indicate protected 一.關於觀察者模式 1.將觀察者與被觀察者分離開來,當被觀察者發生變化時,將通知所有觀察者,觀察者會根據這些變化做出對應的處理。 2.jdk裏已經提供對應的Observer

使用util包裏自帶的接口和類實現觀察模式

註意 簡化 響應 cat pan hang sys ext main 之前的關於觀察者模式的文章,是用自己寫的Observable接口和Observer接口,然後進行實現。其實官方的util包下自帶有實現觀察者模式對應的接口和類,可以簡化我們的代碼結構。 比如我們可

三種觀察模式的C#實現

現在 event 引用 設計 htm num blog 維護 toa 說起觀察者模式,估計在園子裏能搜出一堆來。所以寫這篇博客的目的有兩點: 觀察者模式是寫松耦合代碼的必備模式,重要性不言而喻,拋開代碼層面,許多組件都采用了Publish-Subscribe模式,所以我