使用Repository模式支持产品的客户化

时间:2022-09-13 17:44:37

    本篇博客简单描述了Repository模式在OEA中的应用。


不使用Repository时的问题

    OEA框架中使用了DDD的思想,面向领域对象进行开发。在DDD中,有很多重要的概念,例如:聚合实体对象、值对象、仓储、工厂、服务等。(不太了解的Repository和DDD的朋友,可以看Evans写的《Domain Driven Design》。)

    在OEA中,实体的实现框架使用了CSLA分布式框架。原来为了简单并保持和CSLA开发模式的兼容,一直都把实体的获取模式直接以静态方法的方式直接写在实体的对应列表类中。例如下面这段代码:

使用Repository模式支持产品的客户化

    随着应用的慢慢深入,出现了一些问题:

  1. 不易支持客户化。OEA是基于产品线的开发,如果采用前面的开发模式,当客户化版本扩展了主干版本中的实体类时,由于主干版本中的代码直接使用静态方法,所以无法获取到扩展后的新类型的对象。(要了解OEA中客户化的具体方案,见《基于OEA框架的客户化设计(一) 总体设计》)
  2. 为了使用CSLA而写的这些获取代码,在以后引入非CSLA实体时,可能都需要重写。
  3. DDD的思想在代码中无法直接体现,使得对系统的理解和学习容易产生二意。
  4. 由于使用了静态方法,所以一些通用的代码的重用变得比较过程化,不易读。

    基于以上的原因,团队决定使用Repository模式进行代码的重构。


Repository如何解决以上问题

  1. 如何支持客户化
    当客户版本以继承的方式使用子类B扩展了主干版本的实体类A后,主干版本中原有的代码虽然是面向父类型A的,但是此时其操作的对象应该动态地变为扩展后的子类B。使用Repository模式,我们在主干版本中通过Repository工厂找到需要的类型A的Repository,然后通过它获取具体的对象集合并进行操作。当扩展后,主干版本中同样的代码再次通过RepsotoryFactory获取A的Repository时,得到的其实是子类B的Repository,这样,它获取出来的对象集合都是B的列表。这样,就实现完全的类型扩展,而且主干中的代码不需要任何的改变。
    而一旦实体类被动态扩展,相应的数据层和界面也就被OEA框架自动地进行了调整。
  2. 由于Repository其实是承担了原来的静态方法的职责,也就是实体对象的CDUQ,这些方法现在都变为元状态的Repository的实例方法。这样,通过继承的方式就能很好的实现代码的重用。同时,我们可以在Repository中管理一些整个实体类型的信息,例如某个实体类A的所有属性列表元数据。
  3. 由于Repository模式比较通用,其它实体框架都能比较容易地实现它,所以这样也为OEA以后替换为其它实体框架提供了可能。

    具体的看一下类图:

使用Repository模式支持产品的客户化

    可以看出,整个结构比较简单:

  1. RepositoryFactory通过EntityConvention来检测命名约定,并构建需要的EntityRepository。
  2. 元状态的EntityRepository对Entity和EntityList进行管理(CDUQ)。
  3. 实体类不依赖Repository,而是依赖ILazyProvider接口来实现引用对象或子对象的懒加载。通过ILazyProviderFactory来找到想要的懒加载提供器。
  4. EntityRepository提供ILazyProvider的实现,RepositoryFactory 提供 ILazyProviderFactory的实现。
  5. 具体的RepositoryFactory 被依赖注入到 Entity 层中,并被DIHost保存起来。

小结

    在OEA中使用Repository模式重构后,到目前为止已经使用了一个月左右,大家反应比起原来的调用模式好多了,同时还支持了客户化及其它实体框架引入的可能。总体上来说,重构还是比较成功的。

    在以前其它的系统的开发中,基本上也都使用到了Repository模式,这种模式在数据库应用程序的开发中,确实十分常用。以后可以考虑对它进行一些通用框架层面的设计。