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

《Java网络编程》在第三章线程中讲到了这样一个需求

使用回调的方法从线程中返回信息给对象。

例如,如果有多个对象对线程的计算结果感兴趣,那么线程可以保存一个要回调的对象列表。特定的对象可以通过调用线程类的一个方法把自己添加到这个列表中来完成注册,表示自己对计算结果很感兴趣。如果有多个类的实例对结果感兴趣,可以定义一个新的Observer interface (接口),所有这些类都要实现这个新接口。这个Observer interface将声明回调方法。

以上是观察者模式的典型应用场景。

接下来将上面的需求实现。

 

1. Observer接口

 

声明回调方法update

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

2. 感兴趣的观察者InstanceCallbackDigestUserInterface01

其中将通知者Notifier作为其成员变量

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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值