浅谈反射与特性在接口系统中的应用(编码表转化)


问题描述:

业务系统AB需要共享数据,以达到数据利用最大化,减少工作人员的录入数据的工作量。说明一下,业务系统AB各自使用不同的编码表,简单的说,在业务系统A中,性别是使用0102代表男和女,而在业务系统B中,性别则采用了mw表示男和女。现在,这两个系统要共享性别这个数据项,所以我们需要做的必不可少的工作就是:编码表的转化。这个问题有很高的普遍性,基本上只要是业务系统之间共享数据,那么这一步是必不可少的。今天,我就对此问题谈一谈我的解决之道,供大家探讨。

解决思路:

1) 我们最容易想到的办法就是,编写一个方法,针对输入的编码进行匹配转化,如一下代码所示:

public static string SexCodeToJS(string code)
    
{
            
string result = string.Empty;
            
switch(code.Trim())
            
{
                
case "01":
                    result 
= "m";
                    
break;
                
case "02"
                    result 
= "w";
                    
break;
            }

            
return result;
    }

 

然后,在外部进行调用此方法即可。如果我们的编码表转化数量比较少的话,这一种方法,显然已经可以满足要求了。但假如我们有很多的编码表需要转化,这一种方法使用起来应该是很吃力的。而且,一旦数据项的编码之间对应关系一旦发生变化,我们就必须要改写程序,然后编译、发布。显然此方法的灵活性还不太好。那么我们就需要寻找另一种灵活的,可以应对编码对应关系可能会变的方法。

1) 使用数据库或者xml存储编码表之间的对应关系。使用数据库也好,xml也好,都是把问题的可变性单独分离出来,以数据库存储为例,可以设计如下表结构(脚本如下):

create table CodeConvert
(
id 
int identity(1,1primary key,
codeType 
varchar(10), --编码的类型
codeA varchar(10), --业务系统A的编码
codeA_Name varchar(20), --业务系统A的对应编码的描述
codeB varchar(10),--业务系统B的编码
codeB_Name varchar(20--业务系统B的对应编码的描述
)

 在这个表里存储编码之间的映射关系。现在,如果你需要转化,那么你就需要查询这个表,就可以得到转化后的编码。而且一旦编码之间的对应关系变了,那么你只需要修改这个表里的数据即可完成修改,相对上一种方法,已经增加抗变性。再回头看,抗变性是增加了,可是客户程序使用的时候仍然比较麻烦,仍然需要关心,哪个编码需要转化。其实,从职责分配的角度讲,哪个编码需要转化,是在使用之前就可以确定下来的事情,所以我们可不可以让编码自动转化呢?如果可以的话,那么客户程序就不再需要关心哪个编码需要转化的事情啦,毕竟这是一件烦人的事情。现在,我们整理一下思路,假设有一个负责转化的方法,如下:
public static string ConvertCode(string codeType,string systemACode)
{}
 
那么,目前如果有一个实体类Person需要转化编码的时候,需要调用:
Person p = GetPerson();
p.SexCode 
= ConvertCode("CodeType",p.SexCode);
p.MarriageStatusCode 
= ConvertCode("CodeType",p.MarriageStatusCode);

  可以看出,我们需要知道哪一个属性的编码需要转化。那么,我们希望编码可以自动转化,使用编码转化时,不再关心哪一个属性的编码需要转化,代码如下:
Person p = GetPerson();

= ConvertObjectCode(p); //一次性把所有需要转化的编码全部转化。


这样的代码看起来会比较舒服,客户代码只需要关心何时转化编码,而不关心编码如何转化,这就是职责的分离。

我们应该怎样编写ConvertObjectCode(object convert_obj)方法呢?下面就重点介绍使用反射和特性(自定义属性)就可以做到。

为了更好的提高方法的使用性,我们会给ConvertObjectCode方法添加一个参数,用于指示,编码转化的方向,即:是从业务系统AB还是BA。添加这个参数这个方法就可以做到双向转化啦。

让我们继续探讨ConvertObjectCode方法的功能吧。在这里,这个方法需要做的事情是:转化类的属性编码,但要转化的结果则归属于类的属性,因为每个属性转化后的结果是不一样的,而要转化为什么,类的属性是知道的。所以,在这里我们需要再次细化职责,ConvertObjectCode方法只负责转化,而转化为什么则由类的属性承担。看到这里,可能你已经知道如何做啦,那就看一下代码吧。

首先,需要编写一个特性,用于标注哪一个类的属性需要转化,做何种转化。代码如下:

[AttributeUsage(AttributeTargets.Property,AllowMultiple = false)]
    
public class CodeConvertAttribute:Attribute
    
{
        
public CodeConvertAttribute(string codeType)
        
{
            
this.m_codeType = codeType;
        }

        
private string m_codeType;
        
public string CodeType //编码的类型
        {
            
get
            
{
                
return this.m_codeType;
            }

            
set
            
{
                
this.m_codeType = value;
            }

        }

    }


  其次,在需要做编码转化类的属性上加特性。代码如下:
[CodeConvert(CodeType.Sex)]
        
public string Sex
        
{
            
get
            
{
                
return m_Sex;
            }

            
set
            
{
                
this.m_Sex = value;
            }

        }


  最后,做转化的动作,如下:
/// <summary>
        
/// 自动转化实体类的各个属性的编码(系统A与系统B)
        
/// </summary>
        
/// <param name="convertObj">要转化的对象</param>
        
/// <param name="huNanToLocal">true:A的编码转化为B;false:B的编码转化为A</param>
        
/// <returns></returns>

        public static object AutoConvertCode(object convertObj,bool ToLocal)
        
{
            Type type 
= convertObj.GetType();
            PropertyInfo[] props 
= type.GetProperties(BindingFlags.Instance | BindingFlags.Public);
            
foreach(PropertyInfo p in props)
            
{
                
object convertObj_value = p.GetValue(convertObj,null);
                
string js_type = string.Empty;
                
object[] customerAttributes = p.GetCustomAttributes(typeof(CodeConvertAttribute),false);
                
if(customerAttributes.Length > 0)
                
{
                    CodeConvertAttribute attr 
= (CodeConvertAttribute)customerAttributes[0];
                    js_type 
= attr.CodeType;
                    
if(ToLocal)
                        p.SetValue(convertObj,ConvertCode(js_type,convertObj_value.ToString()),
null);
                    
else
                        p.SetValue(convertObj, ConvertCode (js_type,convertObj_value.ToString()),
null);
                }

                
            }
    
            
return convertObj;
        }


  现在,你就可以轻松的对任意的对象进行编码转化了,如果某个类的属性需要增加编码转化的工作,那么只需要把特性CodeConvert添加到对应的属性上即可,剩下的事情就不用操心啦。怎么样,现在的你还觉得特性和反射遥不可及嘛?

注:之所以写这样的一片post主要是前一段时间,发布了几篇关于反射特性原理的文章,很多朋友都说应用起来有点困难,这一篇就算是对这两篇文章的补充吧。 另外,今天也是一个值得庆祝的日子,因为我自己的小站:问题小站已经开通
了。这篇post也算是给它的贺礼吧。
posted @ 2008-01-21 23:51  小罗  阅读(290)  评论(0编辑  收藏  举报