用DynamicProxy实现POCO ActiveRecord
用DynamicProxy实现POCO ActiveRecord
1. POCO
1.1. 什么是POCO
POCO的概念是从java的POJO((Plain Old Java Objects))借鉴而来,两者的原理是一致的。POJO的由来是EJB的复杂,java的开发者就诞生了POJO。
POCO是指简单C#对象(Plain Old C# Objects)。一个POCO类符合以下条件:
l 没有继承类(class);
l 没有实现接口(interface);
l 不与(第三方)框架发生关系。
POCO的意义就在于它的简单灵活。因为POCO的简单和灵活,使得它能够任意扩展,胜任多个场合,也就让一个模型能够工作在不同的层上,从而带动构架的精简。
1.2. POCO与DO
单纯的POCO只有属性(Property)和字段(Field),没有包含多余的东西。POJO干脆就是一个Javabean。
如果在POCO的基础上扩展为领域对象(DO,Domain Object),那么就会增加方法。注意,扩展不能违背POCO的“简单”原则。
1.3. 领域模型(Domain Model)基于POCO的意义
因为没有从任何其它类继承,对于只能单继承的C#(java也一样)语言,领域模型使用POCO,在实现业务逻辑时有着更自由、更灵活的编码方式。
没有与任何第三方框架发生关系,便于POCO领域模型的单元测试。
因为没有使用任何第三方框架,使得POCO领域模型更容易维护和重用。
1.4. POCO与PO
PO是指持久对象(Persistant Object)。PO的特性就是持久化状态。
PO是与ORM紧密相关的,它通常存与ORM的Session生命周期保持一致,当Session关闭时PO的特性也会丢失。而POCO的生命周期只要不被GC回收(通常是程序主动dispose),就永远存在。
POCO与PO在结构上并无差别,两者可以相互转换。例如NHibernate Session.Get返回的就是一个PO,当我们关闭Session之后,这个PO就会变成POCO,当Session.Update这个POCO,它又会变回PO。
1.5. POCO与VO
这里的VO是指View Object。VO的特性是数据绑定。
当把基于POCO的DO(Domain Object)传递给Presenter层时,DO就变成了VO。在POCO的思想指导下,领域模型(Domain Model)尽量直接暴露给Presenter层使用——需要远程访问或者异构平台除外,这种情况需要增加DTO层和Façade层。
1.6. POCO与DO、PO、VO总结
POCO在不同场合(层)扮演不同的身份:在领域模型层,它是DO;在数据持久层,它是PO;在Presenter层,它是VO。
POCO是一种类设计的思想、一种类设计的指导原则,POCO能够胜任不同场合,使得一个对象贯穿多个层成为现实。
2. ActiveRecord
Martin Flow对ActiveRecord的定义:
An object that wraps a row in a database table or view, encapsulates the database access, and adds domain logic on that data.
2.1. ActiveRecord的特点
每一个数据库表对应创建一个类.类的每一个对象实例对应于数据库中表的一行记录,通常表的每个字段在类中都有相应的Field。
ActiveRecord同时负责把自己持久化。在ActiveRecord中封装了对数据库的访问,即CRUD。
ActiveRecord是一种领域模型(Domain Model),封装了部分业务逻辑。
2.2. ActiveRecord 的适用情况
l 业务逻辑比较简单;当你的类基本上和数据库中的表一一对应时,ActiveRecord是非常方便的,即你的业务逻辑大多数是对单表操作。
l 当发生跨表的操作时,往往会配合使用事务脚本(Transaction Script),把跨表事务提升到事务脚本中。
l ActiveRecord最大优点是简单,、直观,一个类就包括了数据访问和业务逻辑。如果配合代码生成器使用就更方便了。
ActiveRecord特别适合web快速开发。
2.3. ActiveRecord 不适合用的情况
l ActiveRecord虽然有业务逻辑,但基本上都是基于单表的。跨表逻辑一般会放到当发生跨表的操作时,往往会配合使用事务脚本(Transaction Script)中。如果对象间的关联越来越多,你的事务脚本越来越庞大,重复的代码越来越多,你就要考虑Domain Model + O/R Mapper了。
l ActiveRecord保存了数据, 使它有时候看上去像数据传输对象(DTO)。但是ActiveRecord有数据库访问能力,不要把它当DTO用。尤其在跨越进程边界调用的时候,不能传递ActiveRecord对象。
3. DynamicProxy
动态代理是在运行时在内存中构建的一种类型,该类型实现了接口I,但是它将所有的方法调用都转发给类型A。
4. 用DynamicProxy实现ActiveRecord
为了保持领域模型的“干净”,所以Domain Model的类使用Xml而不是Attribute来作ORM的映射。这样当更换ORM框架时,Domain Model的类不会有任何改变——使用Domain Model的业务也不会有改变。
从Domain Model Proxy持久化到DB时,如果类结构与数据表有阻抗,而且这些阻抗与领域模型无关,那么就把这些差异在Domain Model Proxy中实现。在这里,Domain Model Proxy也覆盖了DB Model的功能。