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