在周末的设计过程中,需要用到Observer模式,但当时纠结了一下是否真的需要使用Observer模式,在Google了一下以后,找到了[设计模式]AsyncToken模式,替换通常的Listener模式这篇文章。先贴一下样例代码吧,完整的代码可以参考这个连接
package cn.org.rapid_framework.util.concurrent.async;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import javax.swing.SwingUtilities;
/**
* <pre>
* public void testSendEmail() {
* final String address = "badqiu(a)gmail.com";
* final String subject = "test";
* final String content = "async token test";
* AsyncToken token = sendAsyncEmail(address,subject,content);
*
* token.addResponder(new IResponder() {
* public void onFault(Exception fault) {
* System.out.println("email send fail,cause:"+fault);
* sendAsyncEmail(address,subject,content);
* }
* public void onResult(Object result) {
* System.out.println("email send success,result:"+result);
* }
* });
* }
*
* public AsyncToken sendAsyncEmail(String address,String subject,String content) {
* final AsyncToken token = new AsyncToken();
*
* Thread thread = new Thread(new Runnable() {
* public void run() {
* try {
* //do send email job...
* token.setComplete(executeResult);
* }catch(Exception e) {
* token.setFault(e);
* }
* }
* });
* thread.start();
*
* return token;
* }
* </pre>
* @see AsyncTokenTemplate
* @author badqiu
*/
public class AsyncToken<T> {
public static final String DEFAULT_TOKEN_GROUP = "default";
private static AtomicLong tokenIdSequence = new AtomicLong(1);
//tokenGroup tokenName tokenId
private String tokenGroup = DEFAULT_TOKEN_GROUP;
private String tokenName;
private long tokenId;
private List<IResponder> _responders = new ArrayList(2);
private UncaughtExceptionHandler uncaughtExceptionHandler;
private T _result;
private Exception _fault;
private boolean _isFiredResult;
private CountDownLatch awaitResultSignal = null;
public AsyncToken(){
this(null);
}
public AsyncToken(UncaughtExceptionHandler uncaughtExceptionHandler) {
this(DEFAULT_TOKEN_GROUP,null);
this.uncaughtExceptionHandler = uncaughtExceptionHandler;
}
public AsyncToken(String tokenGroup,String tokenName) {
setTokenGroup(tokenGroup);
setTokenName(tokenName);
this.tokenId = tokenIdSequence.getAndIncrement();
}
public String getTokenGroup() {
return tokenGroup;
}
public void setTokenGroup(String tokenGroup) {
if(tokenGroup == null) throw new IllegalArgumentException("'tokenGroup' must be not null");
this.tokenGroup = tokenGroup;
}
public String getTokenName() {
return tokenName;
}
public void setTokenName(String tokenName) {
this.tokenName = tokenName;
}
public long getTokenId() {
return tokenId;
}
/**
* addResponder(responder,false);
* @param responder
*/
public void addResponder(final IResponder<T> responder) {
addResponder(responder,false);
}
/**
*/
public void addResponder(final IResponder<T> responder,boolean invokeResponderInOtherThread) {
_responders.add(responder);
if(_isFiredResult) {
if(invokeResponderInOtherThread) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
fireResult2Responder(responder);
}
});
}else {
fireResult2Responder(responder);
}
}
}
public List<IResponder> getResponders() {
return _responders;
}
public boolean hasResponder() {
return _responders != null && _responders.size() > 0;
}
public UncaughtExceptionHandler getUncaughtExceptionHandler() {
return uncaughtExceptionHandler;
}
public void setUncaughtExceptionHandler(UncaughtExceptionHandler uncaughtExceptionHandler) {
this.uncaughtExceptionHandler = uncaughtExceptionHandler;
}
private void fireResult2Responder(IResponder responder) {
try {
if(_fault != null) {
responder.onFault(_fault);
}else {
responder.onResult(_result);
}
}catch(RuntimeException e) {
if(getUncaughtExceptionHandler() != null) {
getUncaughtExceptionHandler().uncaughtException(responder, e);
}else {
throw e;
}
}catch(Error e) {
if(getUncaughtExceptionHandler() != null) {
getUncaughtExceptionHandler().uncaughtException(responder, e);
}else {
throw e;
}
}
}
private void fireResult2Responders() {
synchronized (this) {
_isFiredResult = true;
if(awaitResultSignal != null) {
awaitResultSignal.countDown();
}
}
for(IResponder r : _responders) {
fireResult2Responder(r);
}
}
public void setComplete(){
setComplete(null);
}
public void setComplete(T result) {
if(_isFiredResult) throw new IllegalStateException("token already fired");
this._result = result;
fireResult2Responders();
}
public void setFault(Exception fault) {
if(fault == null) throw new NullPointerException();
if(_isFiredResult) throw new IllegalStateException("token already fired");
this._fault = fault;
fireResult2Responders();
}
public boolean isDone() {
synchronized (this) {
return _isFiredResult;
}
}
/**
* @see Future
*/
public Object waitForResult() throws InterruptedException,Exception {
return waitForResult(-1, null);
}
/**
* @see Future
*/
public Object waitForResult(long timeout,TimeUnit timeUnit) throws InterruptedException,Exception {
synchronized(this) {
if(_isFiredResult) {
if(_fault != null) {
throw _fault;
}else {
return _result;
}
}
awaitResultSignal = new CountDownLatch(1);
}
if(timeout > 0) {
awaitResultSignal.await(timeout,timeUnit);
}else {
awaitResultSignal.await();
}
if(_fault != null) {
throw _fault;
}else {
return _result;
}
}
}
文章总结了AsyncTokenVS Observer好处和异同
使用AsyncToken的好处:
1. token可以无限传递,只要对方法的执行结果感兴趣,都可以监听方法的执行结果.
2. 拥有上下文,还可以引用前面的参数,以执行任务email重发这种任务
3. 一个token与一个方法对应,方法调用时你即知道token对应的事件,不需要使用listener模式中的一般用EventType来区别不现的事件
3. 灵活转换,也可以将上面的token再转至listener,再由listener以事件的方式派发事件
与Listener的异同:
1.token可以无限传递
2.没有使用事件或是监听不同的方法,listener一般配合需要使用事件,然后由事件进行参数的绑定.
3.listener模式一般是先设置好listener,而AsyncToken可以得到token后再添加监听方法