首页 > 软件设计 > Oberserver模式的变种AsyncToken

Oberserver模式的变种AsyncToken

2010年3月27日 admin 发表评论 阅读评论

在周末的设计过程中,需要用到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后再添加监听方法

分类: 软件设计 标签:
  1. 2010年3月29日13:54 | #1

    蝴蝶结贵族服饰,2010年我们做的会更好!

  2. 2010年3月29日14:35 | #2

    蝴蝶结贵族服饰.http://shop60655251.taobao.com/

  1. 本文目前尚无任何 trackbacks 和 pingbacks.