ObjectBuilder技术内幕(五)

18 篇文章 0 订阅

ObjectBuilder技术内幕之五

创建器

从前面的论述中,我们看到一个对象的创建过程十分复杂和繁琐,远不是一个new那么简单,涉及到许多对象,创建器上下文、策略、方针等等等等。但由于采用了良好的设计模式,是这些众多的对象协同工作次序井然。创建器采用创建者设计模式,把一系列对象的创建工作加以封装,使调用者只要对其进行配置,然后调用BuildUp就可以得到最后的产品(要创建的对象),或者调用TearDown来销毁对象,BuildUpTearDown是一对开闭操作,你使用BuildUp创建的对象,最好使用TearDown将其销毁。原因我想你也清楚,因为对象的创建如果涉及到其他对象(尤其是在依赖注入的情况下),使用TearDown尤其重要。TearDown会以对象被创建的相反次序卸载对象。下面是我们看创建器的代码的时候了,同样按照惯例从接口开始:

public interface IBuilder<TStageEnum>

{

       PolicyList Policies { get; }

       StrategyList<TStageEnum> Strategies { get; }

 

       object BuildUp(IReadWriteLocator locator, Type typeToBuild, string idToBuild, object existing, params PolicyList[] transientPolicies);

 

       TTypeToBuild BuildUp<TTypeToBuild>(IReadWriteLocator locator, string idToBuild, object existing, arams PolicyList[] transientPolicies);

 

       TItem TearDown<TItem>(IReadWriteLocator locator, TItem item);

}

 

IBuilder接口就像我们期待的那样简单,两个重载的BuildUp版本,一个用于泛型。一个TearDown方法。两个属性:策略表和方针表。

可能你注意到有点和策略接口方法相同,一个区别就是创建器的BuildUp方法参数和策略中的参数不同。由于对象的创建过程需要一个创建器上下文,配置上下文的工作必须由创建器来完成。在IBuilder下是一个抽象的BuilderBase基类, 我们只讲解主要部分:

 

private Dictionary<object, object> lockObjects = new Dictionary<object, object>();

 

该字段成员用于支持多线程操作。

      

public BuilderBase(IBuilderConfigurator<TStageEnum> configurator)

{

       configurator.ApplyConfiguration(this);

}

 

构造器之一,参数configurator是实现了IBuilderConfigurator接口的类实例对象,通过这种方式,创建器的配置工作可以被分离到外部,使得对创建器的使用更加灵活。比如说你可以从IBuilderConfigurator接口实现一个你自己的配置类,然后在ApplyConfiguration方法对传递给方法的Builder对象进行配置(访问者模式的应用)。

 

public virtual object BuildUp(IReadWriteLocator locator, Type typeToBuild,

         string idToBuild, object existing, params PolicyList[] transientPolicies)

{

       if (locator != null)

       {

              lock (GetLock(locator))

              {

                     return DoBuildUp(locator, typeToBuild, idToBuild, existing, transientPolicies);

              }

       }

       else

       {

              return DoBuildUp(locator, typeToBuild, idToBuild, existing, transientPolicies);

       }

 

}

 

基类的默认BuildUp过程,如果定位器不为null,对定位器加锁(阻止其他线程在此期间对它进行访问)。调用DoBuildUp方法。DoBuildUp方法如下:

 

private object DoBuildUp(IReadWriteLocator locator, Type typeToBuild, string idToBuild,

                                          object existing, PolicyList[] transientPolicies)

{

       IBuilderStrategyChain chain = strategies.MakeStrategyChain();

       ThrowIfNoStrategiesInChain(chain);

 

       IBuilderContext context = MakeContext(chain, locator, transientPolicies);

       IBuilderTracePolicy trace = context.Policies.Get<IBuilderTracePolicy>(null, null);

 

       if (trace != null)

              trace.Trace(Properties.Resources.BuildUpStarting, typeToBuild,

idToBuild ?? "(null)");

                    

       object result = chain.Head.BuildUp(context, typeToBuild, existing, idToBuild);

 

       if (trace != null)

              trace.Trace(Properties.Resources.BuildUpFinished, typeToBuild,

idToBuild ?? "(null)");

                    

       return result;

}

 

首先创建策略链,然后调用ThrowIfNoStrategiesInChain检测,如果没有策略(空链)则抛出异常。我们从这里可以看到派生类在调用基类的BuildUp之前,必须先把策略添加到策略表中。接下来是调用MakeContext方法构造创建器上下文环境。接着查询方针表看是否需要跟踪。最后通过调用策略链的第一个策略的BuildUp方法开始对象的创建过程。MakeContext方法如下:

 

private IBuilderContext MakeContext(IBuilderStrategyChain chain,

                  IReadWriteLocator locator, params PolicyList[] transientPolicies)

{

       PolicyList policies = new PolicyList(this.policies);

 

       foreach (PolicyList policyList in transientPolicies)

                     policies.AddPolicies(policyList);

 

       return new BuilderContext(chain, locator, policies);

}

 

构造创建器上下文过程并不复杂,但是这里要注意到一个transierntPolicies参数,这是通过参数传递给BuildUp方法的称为瞬间方针表,也就是说它并未被永久的保存到Builder对象的方针表中,仅在本次的创建过程有效。这种机制允许我们在创建一个特殊对象时避免创建一个新的创建器。

      

public TItem TearDown<TItem>(IReadWriteLocator locator, TItem item)

{

       if (typeof(TItem).IsValueType == false && item == null)

              throw new ArgumentNullException("item");

 

       if (locator != null)

       {

              lock (GetLock(locator))

              {

                     return DoTearDown<TItem>(locator, item);

              }

       }

       else

       {

              return DoTearDown<TItem>(locator, item);

       }

}

对象的拆卸过程,如果要拆卸的对象不是值类型同时是null的话,抛出异常。如果定位器不为空,锁住定位器(理由同BuildUp,然后调用DoTearDown方法,开始拆卸工作。

 

private TItem DoTearDown<TItem>(IReadWriteLocator locator, TItem item)

{

       IBuilderStrategyChain chain = strategies.MakeReverseStrategyChain();

       ThrowIfNoStrategiesInChain(chain);

 

       Type type = item.GetType();

       IBuilderContext context = MakeContext(chain, locator);

       IBuilderTracePolicy trace = context.Policies.Get<IBuilderTracePolicy>(null, null);

 

       if (trace != null)

              trace.Trace(Properties.Resources.TearDownStarting, type);

 

       TItem result = (TItem)chain.Head.TearDown(context, item);

 

       if (trace != null)

              trace.Trace(Properties.Resources.TearDownFinished, type);

 

       return result;

}

 

拆卸对象的过程和创建过程正好相反,首先用一条反向的策略链(和创建过程的策略次序相反),然后调用MakeContext方法创建一个上下文环境,最后调用策略链的第一个策略的TearDown方法开始对象的拆卸过程。

private object GetLock(object locator)

{

       lock (lockObjects)

       {

              if (lockObjects.ContainsKey(locator))

                     return lockObjects[locator];

 

              object newLock = new object();

              lockObjects[locator] = newLock;

              return newLock;

       }

}

加锁机制,使用前面定义的字典对象作为哨兵,如果字典中已经有定位器存在,就返回这个定位器,否则把定位器加入到字典中。

在抽象基类的层次下面,是Builder的具体类,由于基类已经实现了基本的公共操作,剩下的操作由Builder类来完成。Builder类只有一个构造器方法,这个方法我们前面已经看到了。我们没有提到的是最后的两行代码:

 

 

Policies.SetDefault<ICreationPolicy>(new DefaultCreationPolicy());

 

if (configurator != null)

       configurator.ApplyConfiguration(this);

 

代码在设置了策略之后,设置一个指定一个默认的创建方针。最后一个语句作用和基类一样,就不解释了。

我们几乎讲述了OB的全部代码,还有一些例如自定义异常类等,相信你自己就能看明白。另外

CAB中带有OB的单元测试代码,如果你对某个类或者有些方法还不能完全理解的话,可以看相应的测试用例。

后记

OB的设计中,包含了大量的设计模式,比如整个创建器就是创建者设计模式,模式的实现过程包含了责任链设计模式、策略设计模式、组合设计模式、模板方法设计模式、黑板设计模式、访问者设计模式等,每一种设计模式都不是孤立的,如果你对设计模式的使用感到困惑,那么OB就是最好的教材。

本系列作为新年礼物送给大家,希望你们能够喜欢。文稿没有经过校对和润色,有许多错字别字,还望大家多多包涵,如果有什么批评和建议,也请不吝赐教。


(全文完)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值