使用观察者模式实现线程将计算结果回调给多个对象

来源:互联网 发布:酷狗上传的歌网络异常 编辑:程序博客网 时间:2024/06/10 02:27

《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.       运行结果



阅读全文
0 0