您的位置:首页 > 其它

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

2017-07-03 10:40 609 查看
《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.       运行结果

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: