好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

Context+ContextScope——这是否可以看作一种设计模式?

Context+ContextScope——这是否可以看作一种设计模式?

相信大家对TransactionScope都比较熟悉。通过TransactionScope,我们可以很容易地将一组操作纳入同一个事务中;或者说TransactionScope创建一个基于事务的上下文范围,在这个范围内共享一个相同的环境事务(Ambient Transaction)。我个人觉得这体现了一种可以重用的模式,即本篇文章介绍的Context+ContextScope模式,这种模式旨在一定范围内创建一个可以共享的上下文信息。

我们通过一个简单的例子来对Context+ContextScope模式进行简单说明。比如在一个安全级别比较高的GUI应用中,我们需要对用户的每一个UI操作进行安全审核(Auditing,比如记录下当前操作的意图、操作时间和用户名等),我们将这个被审核的UI操作称为“活动(Activity)”。如果我们能够将针对这个UI操作的执行(事件的触发、对业务逻辑的执行以及对数据库的访问)纳入同一个基于活动的上下文中,那么审核就可以直接从当前的环境上下文中获取到相应的审核信息了。[源代码从 这里 下载]

一、ActivityContext

为此,我们创建了如下一个名为ActivityContext的类型表示针对Activity的上下文。ActivityContext具有三个实例属性,其中ActivityName和DateTime表示活动的名称和开始时间,而字典类型的Properties 属性用于维护Activity相关的额外属性。静态Current属性表示当前的环境上下文(Ambient Context),它返回的是静态字段current。值得一提的,在该静态字段上应用了ThreadStaticAttribute特性,意味着静态字段仅仅限于当前的线程。这也说明了Context+ContextScope模式主要应用于同步环境,如果需要对异步环境进行支持,可以做一些额外处理。

    1:   public   class  ActivityContext: IDisposable
    2:  {
    3:      [ThreadStatic]
    4:       private   static  ActivityContext current;
    5:   
    6:       public   string  ActivityName { get;  private  set; }
    7:       public  DateTime StartTime { get;  private  set; }
    8:       public  IDictionary< string ,  object > Properties { get;  private  set; }
    9:   
   10:       internal  ActivityContext( string  activityName)
   11:      {
   12:           this .ActivityName = activityName;
   13:           this .StartTime = DateTime.Now;
   14:           this .Properties =  new  Dictionary< string ,  object >();
   15:      }
   16:   
   17:       public   static  ActivityContext Current
   18:      {
   19:          get {  return  current; }
   20:           internal  set{current =  value ;}
   21:      }
   22:   
   23:       public   void  Dispose()
   24:      {
   25:           foreach  (var property  in   this .Properties.Values)
   26:          {
   27:              IDisposable disposable = property  as  IDisposable;
   28:               if  ( null  != disposable)
   29:              {
   30:                  disposable.Dispose();
   31:              }
   32:          }
   33:      }
   34:  }


二、ActivityContextScope

Context+ContextScope的核心不在于Context而在于ContextScope,即我们需要控制上下文的范围。对于我们的安全审核场景来说,我们需要针对用于的UI操作(比如点击某个按钮)创建ActivityContext,该上下文的生命周期仅限于针对UI事件的响应过程。为此我们创建一个ActivityContextScope类型用于创建ActivityContext并控制其生命周期。如下面的代码片断所示,ActivityContextScope除了接受一个表示创建活动的名称之外,还具有一个ContextScopeOperation枚举类型的参数。

    1:   public   class  ActivityContextScope: IDisposable
    2:  {
    3:       private  ActivityContext current = ActivityContext.Current;
    4:       private  ActivityContext newContext;
    5:   
    6:       public  ActivityContextScope( string  activityName, ContextScopeOption contextScopeOption = ContextScopeOption.Required)
    7:      {
    8:           switch  (contextScopeOption)
    9:          {
   10:               case  ContextScopeOption.Required:
   11:                  {
   12:                       if  ( null  == current)
   13:                      {
   14:                          ActivityContext.Current = newContext =  new  ActivityContext(activityName);
   15:                      }
   16:                       break ;
   17:                  }
   18:               case  ContextScopeOption.RequiresNew:
   19:                  {
   20:                      ActivityContext.Current = newContext =  new  ActivityContext(activityName);
   21:                       break ;
   22:                  }
   23:               case  ContextScopeOption.Suppress:
   24:                  {
   25:                      ActivityContext.Current =  null ;
   26:                       break ;
   27:                  }
   28:          }
   29:      }
   30:   
   31:       public   void  Dispose()
   32:      {
   33:          ActivityContext.Current = current;
   34:           if  ( null  != newContext)
   35:          {
   36:              newContext.Dispose();
   37:          }
   38:      }
   39:  }
   40:   
   41:   public   enum  ContextScopeOption
   42:  {
   43:      Required,
   44:      RequiresNew,
   45:      Suppress
   46:  }

考虑在创建ActivityContextScope的时候,当前环境上下文可能已经存在,那么是重用现成的上下文还是创建新的上下文,可以通过ContextScopeOperation枚举来控制。该枚举类型的Required和RequiredNew选项分别表示重用现有上下文和创建新的上下文。另一个选项Supress表示创建一个“无环境上下文”的范围,比如TransactionScope通过类似的机制将不需要纳入事务的操作(比如Logging)从环境事务中剥离出来。基于ContextScopeOperation的ActivityContext创建机制体现在ActivityContextScope的构造函数中。ActivityContextScope实现了IDisposable接口,在实现的Dispose方法中我们将通过ActivityContext的静态属性Current表示的环境上下文恢复到ActivityContextScope创建之前的状态。

三、ActivityContextScope的使用

我们通过如下一个简单的实例来演示ActivityContextScope的使用。在Main方法中我们在一个基于“Activty1”的ActivityContextScope中调用Activty1方法。在Activty1方法中,我们在一个基于“Activty2”的ActivityContextScope中调用Activty2方法。两次创建ActivityContextScope都采用默认的ContextScopeOperation(Required)。在方法Activty2中,我们在一个基于“Activty3”的ActivityContextScope中调用Activty3方法,创建ActivityContextScope时选择RequiredNew选项。而在Activty3方法中,我们针对Supress选项创建ActivityContextScope并调用Activity4方法。方法Activty1、Activty2、Activty3和Activty4中均调用DisplayCurrentContext将当前的ActivityContext信息打印出来。

    1:   class  Program
    2:  {
    3:       static   void  Main( string [] args)
    4:      {
    5:           using  (ActivityContextScope contextScope =  new  ActivityContextScope( "Activty1" ))
    6:          {
    7:              Activty1();
    8:          }
    9:      }
   10:   
   11:       static   void  DisplayCurrentContext( string  methodName)
   12:      {
   13:           if  ( null  != ActivityContext.Current)
   14:          {
   15:              Console.WriteLine( "{0}: Current ambient activity is {1}" , methodName, ActivityContext.Current.ActivityName);
   16:          }
   17:           else 
   18:          {
   19:              Console.WriteLine( "{0}: No ambient activity." , methodName);
   20:          }
   21:      }
   22:   
   23:       private   static   void  Activty1()
   24:      {
   25:          DisplayCurrentContext( "Activty1" );
   26:           using  (ActivityContextScope contextScope =  new  ActivityContextScope( "Activty2" ))
   27:          {
   28:              Activty2();
   29:          }
   30:      }
   31:   
   32:       private   static   void  Activty2()
   33:      {
   34:          DisplayCurrentContext( "Activty2" );
   35:           using  (ActivityContextScope contextScope =  new  ActivityContextScope( "Activty3" , ContextScopeOption.RequiresNew))
   36:          {
   37:              Activty3();
   38:          }
   39:      }
   40:   
   41:       private   static   void  Activty3()
   42:      {
   43:          DisplayCurrentContext( "Activty3" );
   44:           using  (ActivityContextScope contextScope =  new  ActivityContextScope( "" , ContextScopeOption.Suppress))
   45:          {
   46:              Activty4();
   47:          }
   48:      }
   49:   
   50:       private   static   void  Activty4()
   51:      {
   52:          DisplayCurrentContext( "Activty4" );
   53:      }
   54:  }

上面这段程序执行之后会在控制台上生成如下的输出结果,我们可以看到当前环境上下文是严格按照我们创建ActivityContextScope的方式来控制的。

    1:  Activty1: Current ambient activity is Activty1
    2:  Activty2: Current ambient activity is Activty1
    3:  Activty3: Current ambient activity is Activty3
    4:  Activty4: No ambient activity.

作者: Artech
出处: http://artech.cnblogs.com/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

分类:  [03] 设计模式

作者: Leo_wl

    

出处: http://www.cnblogs.com/Leo_wl/

    

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

版权信息

查看更多关于Context+ContextScope——这是否可以看作一种设计模式?的详细内容...

  阅读:40次