我的框架(6)——用动态代理简化实体模型

由一个公共基类实现IPersistable接口,所有实体都从公共基类继承是一种实现方式。这种方式最大的毛病是,实体层会带有一些和基类相关的特性。一般来说,实体层的公共基类往往会带有一些和框架相关的特性,从而导致实体层也和框架的开发模式、设计意图结合得比较紧密,以至于在别的项目中重用时会出现一些完全无关、甚至比较牵强的东西。

在我的理解中,实体本身具有自己领域内部的行为(逻辑),然后通过一个或多个实体的数据或是行为共同构成业务逻辑。相对业务逻辑来说,实体是比较稳定的,重用的可能性更高,业务逻辑可能随着不同的企业有着或多或少的区别。因此实体模型应该越简单越好,越独立越好,最佳的情况是实体和具体的框架没有任何具体联系,最多加上点CustomAttribute就好了。

 

拿上一篇《我的框架(5)——用最原始的方法实现实体的原型》中的那个User举例子,最好就是去掉继承,直接定义一个对象就ok了。比如:

class User
{
    
public string Name{getset;}

    
public int Age{getset;}
}

要实现在一个普通的对象上附加些新功能,首先想到的就是动态代理。曾经考虑过自己来实现,但后来觉得“拿来主义”才是王道,因此毫不犹豫地选择了Castle.DynamicProxy

   

动态代理的关键是IInterceptor接口,通过实现IInterceptor来构造一个自己的拦截器。不过说实话我对动态代理也没有太深入的研究,所以这里给出的只是我自己的做法“用拦截器来完成要由基类做的事情”。

持久化截获器PersistentInterceptor的实现:

#region PersistentInterceptor
/// <summary>
/// 持久化截获器
/// </summary>
[Serializable]
class PersistentInterceptor<T> : IInterceptor
    
where T : classnew()
{
    
#region Ghost
    
private T m_Ghost = null;
    
/// <summary>
    
/// 原始数据
    
/// </summary>
    
private T Ghost
    {
        
get
        {
            
return m_Ghost;
        }
    }
    
#endregion
    
    
#region UseCustomState
    
private bool m_UseCustomState = false;
    
/// <summary>
    
/// 是否使用自定义状态
    
/// </summary>
    
public bool UseCustomState
    {
        
get
        {
            
return m_UseCustomState;
        }
    }
    
#endregion
 
    
#region EntityState
    
private EntityState m_EntityState = EntityState.Added;
    
/// <summary>
    
/// 实体状态
    
/// </summary>
    
private EntityState EntityState
    {
        
get
        {
            
return m_EntityState;
        }
        
set
        {              
            m_EntityState 
= value;
            m_UseCustomState 
= true;
        }
    }
    
#endregion
 
    
#region GetEntityState
    
/// <summary>
    
/// 获取实体的状态
    
/// </summary>
    
/// <param name="entity">实体</param>
    
/// <returns>实体的状态</returns>
    
private EntityState GetEntityState(T entity)
    {
        
if(UseCustomState)
        {
            
return m_EntityState;
        }
        
else
        {
            
if(Ghost == null)
            {
                
return EntityState.Added;
            }
            
else
            {
                
if(SmartCompare(entity, Ghost))
                {
                    
return EntityState.Unchanged;
                }
                
else
                {
                    
return EntityState.Modified;
                }
            }
        }
    }
    
#endregion
 
    
#region MarkDeleted
    
/// <summary>
    
/// 将实体标记为需要删除的
    
/// </summary>
    
/// <param name="entity">实体</param>
    
private void MarkDeleted(T entity)
    {
        EntityState state 
= GetEntityState(entity);
        
if(state == EntityState.Added || state == EntityState.Detached)
        {
            EntityState 
= EntityState.Detached;
        }
        
else
        {
            EntityState 
= EntityState.Deleted;
        }
    }
    
#endregion
 
    
#region PrepareGhost
    
/// <summary>
    
/// 准备原始数据
    
/// </summary>
    
/// <returns>T的实例</returns>
    
private T PrepareGhost()
    {
        
if(m_Ghost == null)
        {
            
lock(this)
            {
                
if(m_Ghost == null)
                {
                    m_Ghost 
= Proxy.Get<T>();
                }
            }
        }
        
return m_Ghost;
    }
    
#endregion
 
    
#region LoadFrom
    
/// <summary>
    
/// 从DbDataReader加载数据
    
/// </summary>
    
/// <param name="entity">实体</param>
    
/// <param name="dataReader">DbDataReader</param>
    
private void LoadFrom(T entity, DbDataReader dataReader)
    {
        EntityDescriptor.DataReader2Entity(dataReader, entity);
        AcceptChanges(entity);
    }
    
#endregion
 
    
#region LoadFrom
    
/// <summary>
    
/// 从DataRow加载数据
    
/// </summary>
    
/// <param name="entity">实体</param>
    
/// <param name="dataRow">DataRow</param>
    
private void LoadFrom(T entity, DataRow dataRow)
    {

        ....
    }
    
#endregion
 
    
#region SaveTo
    
/// <summary>
    
/// 将数据保存到DataRow
    
/// </summary>
    
/// <param name="entity">实体</param>
    
/// <param name="dataRow">DataRow</param>
    
private void SaveTo(T entity, DataRow dataRow)
    {
        ....
    }
    
#endregion
 
    
#region ToDbCommand
    
/// <summary>
    
/// 将数据保存到command的参数
    
/// </summary>
    
/// <param name="entity">实体</param>
    
/// <param name="engine">数据引擎</param>
    
/// <param name="commandAction">DbCommand的动作(插入、修改、删除)</param>
    
private DbCommand ToDbCommand(T entity, DbEngine engine, CommandAction commandAction)
    {
        ....
    }
    
#endregion
 
    
#region AcceptChanges
    
/// <summary>
    
/// 接受改变
    
/// </summary>
    
/// <param name="entity">实体</param>
    
private void AcceptChanges(T entity)
    {
        .... 
    }
    
#endregion
 
    
#region RejectChanges
    
/// <summary>
    
/// 撤销改变
    
/// </summary>
    
/// <param name="entity">实体</param>
    
private void RejectChanges(T entity)
    {
        ....
    }
    
#endregion
 
    
#region SmartCopy
    
/// <summary>
    
/// 智能复制(复制所有带有ColumnAttribute的属性)
    
/// </summary>
    
/// <param name="entity">实体</param>
    
/// <returns>实体的新实例</returns>
    
private object SmartCopy(T entity)
    {
        ....  
    }
    
#endregion
 
    
#region SmartCompare
    
/// <summary>
    
/// 智能比较(比较所有带有ColumnAttribute的属性)
    
/// </summary>
    
/// <param name="entity">实体</param>
    
/// <param name="other">需要比较的对象</param>
    
/// <returns>比较的结果相同则返回true,否则返回false</returns>
    
private bool SmartCompare(T entity, object other)
    {
        ....
    }
    
#endregion
 
    
#region SmartAssign
    
/// <summary>
    
/// 智能赋值(赋值所有带有ColumnAttribute的属性)
    
/// </summary>
    
/// <param name="entity">实体</param>
    
/// <param name="other">需要赋值的对象</param>
    
private void SmartAssign(T entity, object other)
    {
        ....  
    }
    
#endregion
 
    
#region IInterceptor Members

    #region Intercept
    
/// <summary>
    
/// 拦截
    
/// </summary>
    
/// <param name="invocation">调用的信息</param>
    
public void Intercept(IInvocation invocation)
    {
        T entity 
= invocation.Proxy as T;
        
switch(invocation.Method.Name)
        {
            
case "get_State":
            {
                invocation.ReturnValue 
= GetEntityState(entity);
                
break;
            }
            
case "set_State":
            {
                EntityState 
= (EntityState)(invocation.Arguments[0]);
                
break;
            }
            
case "get_EntityType":
            {
                invocation.ReturnValue 
= EntityDescriptor.EntityType;
                
break;
            }
            
case "get_CurrentDbSessionType":
            {
                invocation.ReturnValue 
= CurrentDbSessionType;
                
break;
            }
            
case "set_CurrentDbSessionType":
            {
                CurrentDbSessionType 
= (Type)(invocation.Arguments[0]);
                
break;
            }
            
case "LoadFrom":
            {
                
if(invocation.Arguments[0is DataRow)
                {
                    LoadFrom(entity, (DataRow)(invocation.Arguments[
0]));
                }
                
else if(invocation.Arguments[0is DbDataReader)
                {
                    LoadFrom(entity, (DbDataReader)(invocation.Arguments[
0]));
                }
                
break;
            }
            
case "SaveTo":
            {
                SaveTo(entity, (DataRow)(invocation.Arguments[
0]));
                
break;
            }
            
case "ToDbCommand":
            {
                invocation.ReturnValue 
= ToDbCommand(entity, (DbEngine)         (invocation.Arguments[0]), (CommandAction)(invocation.Arguments[1]));
                
break;
            }
            
case "SmartCopy":
            {
                invocation.ReturnValue 
= SmartCopy(entity);
                
break;
            }
            
case "SmartCompare":
            {
                invocation.ReturnValue 
= SmartCompare(entity, invocation.Arguments[0]);
                
break;
            }
            
case "SmartAssign":
            {
                SmartAssign(entity, invocation.Arguments[
0]);
                
break;
            }
            
case "AcceptChanges":
            {
                AcceptChanges(entity);
                
break;
            }
            
case "RejectChanges":
            {
                RejectChanges(entity);
                
break;
            }
            
case "MarkDeleted":
            {
                MarkDeleted(entity);
                
break;
            }
            
default:
            {
                invocation.Proceed();
             
                
break;
            }
        }
    }
    
#endregion
    
#endregion      
}
#endregion

用于获取实体代理对象的Proxy的实现:

#region QueryAdditionalInterfacesHandler
/// <summary>
/// 获取附加接口的Type的委托
/// </summary>
/// <param name="additionalInterfaces">已附加的接口的Type的集合</param>
public delegate void QueryAdditionalInterfacesHandler(List<Type> additionalInterfaces);
#endregion
 
#region QueryInterceptorsHandler
/// <summary>
/// 获取拦截器的委托
/// </summary>
/// <param name="interceptors">已附加的拦截器的集合</param>
public delegate void QueryInterceptorsHandler(List<IInterceptor> interceptors);
#endregion
 
#region Proxy
/// <summary>
/// <para>代理生成器</para>
/// <para>仅对加入virtual的方法进行拦截,因此实体中的映射属性必须是virtual</para>
/// <para>根据需要附加的接口的Type以及拦截器的集合创建代理</para>
/// </summary>
public class Proxy
{
    
#region QueryAdditionalInterfaces
    
/// <summary>
    
/// 获取附加接口的事件
    
/// </summary>
    
public static event QueryAdditionalInterfacesHandler QueryAdditionalInterfaces = null;

    
#endregion
 
    
#region QueryInterceptors
    
/// <summary>
    
/// 获取拦截器的事件
    
/// </summary>
    
public static event QueryInterceptorsHandler QueryInterceptors = null;
    
#endregion
 
    
#region ProxyGenerator
    
private static ProxyGenerator m_ProxyGenerator = null;
    
/// <summary>
    
/// 代理生成器
    
/// </summary>
    
private static ProxyGenerator ProxyGenerator
    {
        
get
        {
            
if(m_ProxyGenerator == null)
            {
                
lock(typeof(Proxy))
                {
                    
if(m_ProxyGenerator == null)
                    {
                        m_ProxyGenerator 
= new ProxyGenerator();
                    }
                }
            }
            
return m_ProxyGenerator;
        }
    }
    
#endregion
 
    
#region PrepareAdditionalInterfaces
    
/// <summary>
    
/// 准备需要附加的接口的Type的集合
    
/// </summary>
    
/// <returns>需要附加的接口的Type的集合</returns>
    
private static List<Type> PrepareAdditionalInterfaces()
    {
        List
<Type> additionalInterfaces = new List<Type>();
        
if(QueryAdditionalInterfaces != null)
        {
            QueryAdditionalInterfaces(additionalInterfaces);
        }       
        
return additionalInterfaces;
    }
    
#endregion
 
    
#region PrepareInterceptor
    
/// <summary>
    
/// 准备需要附加的拦截器的集合
    
/// </summary>
    
/// <returns>需要附加的拦截器的集合</returns>
    
private static List<IInterceptor> PrepareInterceptors<T>()
        
where T : classnew()
    {
        List
<IInterceptor> interceptors = new List<IInterceptor>();
        
if(QueryInterceptors != null)
        {
            QueryInterceptors(interceptors);
        }
        
return interceptors;
    }
    
#endregion
 
    
#region CreateProxy
    
/// <summary>
    
/// 根据需要附加的接口的Type以及拦截器的集合创建代理
    
/// </summary>
    
/// <typeparam name="T">需要代理的Type</typeparam>
    
/// <param name="additionalInterfaces">需要附加的接口的Type的集合</param>
    
/// <param name="interceptors">需要附加的拦截器的集合</param>
    
/// <returns>指定类型T的代理的实例</returns>
    
private static T CreateProxy<T>(List<Type> additionalInterfaces, List<IInterceptor> interceptors)
        
where T : classnew()
    {
        Type targetType 
= typeof(T);
        EntityDescriptor.Get(targetType);
        
return ProxyGenerator.CreateClassProxy(typeof(T),
                  additionalInterfaces.ToArray(),
                  interceptors.ToArray()) 
as T;
    }
    
#endregion
 
    
#region Get
    
/// <summary>
    
/// <para>获取代理(如果对象已实现IPersistable则直接返回它的实例)</para>
    
/// <para>如果附加的接口的Type中已经包括了IPersistable则不会创建默认的代理对象</para>
    
/// <para>如果附加的的接口的Type数为0,且需要代理的类型已经实现了IPersistable接口,则直接返回该类型的实例</para>
    
/// </summary>
    
/// <typeparam name="T">需要代理的类型</typeparam>
    
/// <returns>指定类型T的代理的实例</returns>
    
public static T Get<T>()
        
where T : classnew()
    {
        List
<Type> additionalInterfaces = PrepareAdditionalInterfaces();
        List
<IInterceptor> interceptors = PrepareInterceptors<T>();
        
if(typeof(T).IsSubclassOf(typeof(IPersistable)))
        {              
            
if(interceptors.Count == 0)
            {
                
return new T();
            }
            
else
            {
                
return CreateProxy<T>(additionalInterfaces, interceptors);
            }
        }
        
else
        {
            
if(!additionalInterfaces.Contains(typeof(IPersistable)))
            {
                additionalInterfaces.Add(
typeof(IPersistable));
                interceptors.Add(
new PersistentInterceptor<T>());
            }
            
return CreateProxy<T>(additionalInterfaces, interceptors);
        }
    }
    
#endregion
}
#endregion

由于我这个人比较讨厌一大堆的配置文件,所以附加的拦截器和接口,我是用静态事件QueryAdditionalInterfacesQueryInterceptors来实现。

 

现在,上面说的那个User在使用的时候只要简单地写成User user = Proxy.Get<User>()就可以包含《我的框架(5)——用最原始的方法实现实体的原型》中由基类实现的所有细节了。Proxy对象的代码中也可以看出:1、类型T本身就已经实现了IPersistable接口,则不使用默认的持久化截获器。2、通过QueryAdditionalInterfaces事件附加的接口中包含IPersistable,也不使用默认的持久化截获器。3、如果前2种情况都不存在,就使用默认的持久化截获器。

 

综上所述,配合《我的框架(2)——元数据》《我的框架(4)——与数据库交互》中的DbSession我们会得到的好处如下:1、实体层和框架完全解耦。2、可以由使用者自己实现持久化截获器,以得到更高的效率或者便利。3、可以方便地附加其他截获器,如:数据权限控制、异常日志、一对多或多对多关联加载等等。4、即使没有源代码也可以很方便地加入由其他团队实现的实体层或是基于其他框架的实体模型。5、如果不喜欢动态代理喜欢公共基类,也可以像《我的框架(5)——用最原始的方法实现实体的原型》那样来实现。

posted @ 2009-08-07 13:09 陈鹏(偶是坏人) 阅读(2268) 评论(3) 编辑 收藏