相信经过那个单元测试您可能要对重新定义的这个创建者刮目相看了,因为无需Director的指导,他可以根据每个产品类型自己的定义,动态的找到它需要执行的每个BuildPart()步骤。实现上相对复杂了一些,不过放在项目中有如下优势:
不必反反复复的编写创建者甲、创建者乙了,只要为自己的产品类型“贴上了标签”(增加这个属性),剩下的就交给创建者自己完成好了;
操作上更加简洁和统一,就一个BuildUp方法,至于构造出的产品类型在Builder<T>的类型参数已经定义,使用上客户程序代码也都非常统一;
这里把BuildStepAttribute给封上了,实际项目中完全可以突破这个限制,把Times、Sequence通过配置文件告诉BuildStepAttribute;
性能改进:
不过从性能角度看,通过反射回调每个BuildPart()步骤似乎有些慢,而且每次BuildUp()的时候都需要通过反射动态获取IList<BuildStepAttbite>似乎也太啰嗦。针对后者这个问题可以参考Enterprise Library中数据访问块自动发现存储过程参数列表的办法,增加一个缓冲,确保获取IList<BuildStepAttribute>的步骤仅执行一次,例如:
C#(很明显,上面的设计并不是线程安全的,实际项目中您可以把Cache设计成一个独立的线程安全的Singleton类型,由这个Singleton实例维护所有的Type / IList<BuildStepAttribute>对应关系) 。
private static IDictionary<Type, IList<BuildStepAttribute>> cache =
new Dictionary<Type, IList<BuildStepAttribute>>();
protected virtual IList<BuildStepAttribute> DiscoveryBuildSteps()
{
if (!cache.ContainsKey(typeof(T)))
{
// … …
}
return cache[typeof(T)];
}
总结:
在整个创建型模式中,创建者模式往往被用来做一些“精细活”,他除了创建对象之外还要负责把复杂的对象及其他的每个部分组装起来,由于“组装工艺”的不同,构造出来的产品可能完全不一样。但工程中,我们还有很多扩展,比如本文为了不用一遍又一遍的实现IBuilder,我们给待构造目标对象的某些方法“贴上标签”,借助反射和Attribute,我们实现了一个具有动态发现机制的Builder。