利用委托与泛型解决功能代码重复问题

最近在做项目(其实就是开发一些WebService接口)的时候,遇到了这么一个问题:就是每个接口都要去实现日志记录的功能,当然记录的内容尽可能的详细,以便根据这些信息还原现场,排除故障。这样,每个接口方法为了实现记录日志的功能,会有很多重复的功能代码。插入下面函数形式说明,可能会更清楚的理解我想要表达的意思:

        public object MothodName(string strValide, string p1, string p2, string p3)

        {

            //1、如果有权限,则可以进行操作。

            if (strValide == "true")

            {

                //log 权限验证结果

                //log 形参名称极其对应的值

                //2、一次检查p1,p2,p3……等参数,确定他们都符合条件

                if (p1 == "true" && p2 == "true" && p3 == "true")

                {

                    try

                    {

                        //do action;

                        //log  result;

                    }

                    catch (Exception e)

                    {

                        //log exception;

                    }

                }

                else 

                {

                    //log error

                }



                //3、

            }

            else

            {

                //log

            }

            return new object();//返回一个东西,知识象征性的返回一个对象

        }

 

大家注意:上面的代码中只有do action 才是这个接口真正需要完成的动作,其它的都是和其他接口一样,必须实现的功能部分。如果每写一个接口都去实现这写具有共性的功能,无疑是一件令人枯燥的重复性工作。我们是搞程序的,而程序就是为了解决重复性的工作产生的。所以如果程序本身是重复性的,那该是一个多么好笑的笑话。是时候该终结它了。

给出我的解决方案:delegate + generic ,也就是委托+泛型。

首先定义一个泛型类,这个泛型类主要用于记录接口的入参类型极其对应的值。因为我们知道,每个接口的参数列表是不一样的,也就是参数类型和参数个数是不确定的。这里为了解决参数类型未知的问题,用泛型。泛型类的定义如下:

    public class ProxyParam<TT>

    {

        private string pName;



        /// <summary>

        /// parameter name

        /// </summary>

        public string PName

        {

            get { return pName; }

            set { pName = value; }

        }

        private TT pval;



        /// <summary>

        /// parameter value

        /// </summary>

        public TT Pval

        {

            get { return pval; }

            set { pval = value; }

        }



        public ProxyParam(string strName,TT val)

        {

            pName = strName;

            pval = val;

        }

    }

至于接口的参数个数未知的问题:我们定义一个ArrayList。参数有多少个,我们就往ArrayList实例里增加多少个元素就完事了,注意这里元素的类型可能是不一样的。而这个实例呢,要作为完成接口共性功能的代理类的一个数据成员。

下面来构造这个完成接口共性功能的代理类:

由于代理类要完成共性功能,因此需要一个处理这些共性问题的方法。

由于代理类要满足各个接口个性需要,也就是上面说的do action。因此要暴漏一个delegate,供接口注册方法。

又由于每个接口的返回值类型是不一样的,这个代理类又必须是一个泛型类。

该代理类的结构定义如下:

  1     /// <summary>

  2     /// the proxy to write log, and invoke the main function of the interface. 

  3     /// </summary>

  4     /// <typeparam name="T">the type of the returned model</typeparam>

  5     public class ProxyInterface<T>

  6     {

  7         /// <summary>

  8         /// the static object to write log to txt files.

  9         /// </summary>

 10         private static ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

 11 

 12         private static JavaScriptSerializer jss = new JavaScriptSerializer();

 13 

 14 

 15         private ArrayList arParams = null;//记录接口的参数列表

 16 

 17         public ArrayList ArParams

 18         {

 19             get

 20             {

 21                 if (arParams == null)

 22                 {

 23                     arParams = new ArrayList();

 24                 }

 25                 return arParams;

 26             }

 27         }

 28 

 29         /// <summary>

 30         /// return a Model<T>

 31         /// </summary>

 32         /// <param name="arParams"></param>

 33         /// <returns></returns>

 34         public delegate Mod_T<T> DelFuncModel(ArrayList arParams);

 35         private event DelFuncModel OnDelFuncModel;

 36         /// <summary>

 37         /// registe the delegate function

 38         /// </summary>

 39         /// <param name="d"></param>

 40         public void RegFuncModel(DelFuncModel d)

 41         {

 42             if (OnDelFuncModel == null)

 43                 OnDelFuncModel = d;

 44         }

 45 

 46         /// <summary>

 47         /// unregiste the delegate function

 48         /// </summary>

 49         /// <param name="d"></param>

 50         public void UnRegFuncModel(DelFuncModel d)

 51         {

 52             OnDelFuncModel -= d;

 53         }

 54         /// <summary>

 55         /// return a Model List<T>

 56         /// </summary>

 57         /// <param name="arParams"></param>

 58         /// <returns></returns>

 59         public delegate Mod_ListT<T> DelFuncList(ArrayList arParams);

 60         private event DelFuncList OnFuncList;

 61         /// <summary>

 62         /// registe the delegate function

 63         /// </summary>

 64         /// <param name="d"></param>

 65         public void RegFuncList(DelFuncList d)

 66         {

 67             if (OnFuncList == null)

 68                 OnFuncList = d;

 69         }

 70 

 71         /// <summary>

 72         /// unregiste the delegate function

 73         /// </summary>

 74         /// <param name="d"></param>

 75         public void UnRegFuncList(DelFuncList d)

 76         {

 77             OnFuncList -= d;

 78         }

 79 

 80         /// <summary>

 81         /// excute the delegate

 82         /// </summary>

 83         /// <param name="param">给调用方的一个编码</param>

 84         /// <param name="intInterfaceCode">接口的编号</param>

 85         /// <param name="strInterfaceDescript">the interface description</param>

 86         /// <param name="alParamList">the interface parameter list</param>

 87         /// <returns></returns>

 88         public Mod_T<T> InvokeTheFunction(string param, int intInterfaceCode, string strInterfaceDescript)

 89         {

 90             Mod_T<T> Mod_obj = new Mod_T<T>();

 91             StringBuilder StrbParams = new StringBuilder(100,5000);//最多记录5000个字

 92             StrbParams.Append("--------------------------begin-------------------------\r\n");

 93             StrbParams.Append(strInterfaceDescript + " " + intInterfaceCode + " 输入参数列表:\r\n");

 94             //序列化

 95             string strParams = jss.Serialize(this.ArParams);

 96             StrbParams.Append(strParams + "\r\n");//注意:这时候记录的参数列表是一个将形参名称极其对应值序列化成Json串。

 97             Authentication auth = CheckUser(param, intInterfaceCode);//判断权限

 98             StrbParams.Append("身份验证结果:" + auth.LoginCode + "\r\n");

 99             if (auth == true)

100             {

101                 try

102                 {

103                     if (OnDelFuncModel != null)

104                     {//执行代理

105                         Mod_obj = OnDelFuncModel(this.ArParams);// 这里处理do action,处理每个接口真正要完成的功能

106                         StrbParams.Append(string.Format("处理成功。\r\n返回的编码:{0}\r\n返回的说明信息:{1}\r\n返回的结果信息:{2}\r\n", Mod_obj.ReturnCode, Mod_obj.ReturnMessage == null ? "" : Mod_obj.ReturnMessage, Mod_obj.T_obj == null ? "" : Mod_obj.T_obj.ToString()));

107                     }

108                 }

109                 catch (Exception e)

110                 {

111                     StrbParams.Append("处理异常:" + e.Message + "\r\n" + e.Source + "\r\n" + e.StackTrace);

112                 }

113             }

114             else

115             {

116             }

117             StrbParams.Append("--------------------------end-------------------------\r\n");

118             log.Info(StrbParams.ToString());

119             return Mod_obj;

120         }

121     }

注意:上面的类只能完成一部分功能。细心的同学会发现我并没有实现DelFuncList的函数。其实只是返回值不同而已大体功能一样。一个返回值是一个对象,另一个返回值的一个对象的集合。

代理类有了,那么如何使用呢?

定义一个WebService Interface接口如下:

 1         public Mod_T<string> exampleFunction(string param, string strUserID, string strUserRealName, string strUserGender, string strUserTel, string strUserEmail, string strUserCertificateType, string strUserCertificateNumber)

 2         {

 3             ProxyInterface<string> pi = new ProxyInterface<string>();

 4             pi.ArParams.Add(new ProxyParam<string>("strUserID", strUserID));

 5             pi.ArParams.Add(new ProxyParam<string>("strUserRealName", strUserRealName));

 6             pi.ArParams.Add(new ProxyParam<string>("strUserGender", strUserGender));

 7             pi.ArParams.Add(new ProxyParam<string>("strUserTel", strUserTel));

 8             pi.ArParams.Add(new ProxyParam<string>("strUserEmail", strUserEmail));

 9             pi.ArParams.Add(new ProxyParam<string>("strUserCertificateType", strUserCertificateType));

10             pi.ArParams.Add(new ProxyParam<string>("strUserCertificateNumber", strUserCertificateNumber));

11             pi.RegFuncModel(UUI);//为代理注册方法。

12             return pi.InvokeTheFunction(param,123456,"测试例子");

13         }

14 

15         private Mod_T<string> UUI(ArrayList ar)

16         {

17             Mod_T<string> mod = new Mod_T<string>();

18             t_Users Model = BLL_Users.Instance.GetById(((ProxyParam<string>)ar[0]).Pval);

19             if (Model != null)

20             {

21                 Model.c_realName = ((ProxyParam<string>)ar[1]).Pval;

22                 Model.c_gender = ((ProxyParam<string>)ar[2]).Pval; ;

23                 Model.c_mobile = ((ProxyParam<string>)ar[3]).Pval ;

24                 Model.c_email = ((ProxyParam<string>)ar[4]).Pval;

25                 Model.c_IDType = ((ProxyParam<string>)ar[5]).Pval;

26                 Model.c_IDNo = ((ProxyParam<string>)ar[6]).Pval;

27                 if (BLL_Users.Instance.Modify(Model))

28                 {

29                     mod.ReturnCode = 200;

30                     mod.T_obj = "true";

31                 }

32                 else

33                 {

34                     mod.ReturnCode = 212;

35                     mod.ReturnMessage = "请重试!";

36                     mod.T_obj = "false";

37                 }

38             }

39             return mod;

40         }

大致就是:如果按照原来的方法,一个接口就是一个方法。现在呢,我将其拆分成两个方法,一个是定义接口,并在这个接口中实例化代理类的一个对象,为这个对象的代理注册第二个方法。而第二个方法才是实现接口功能的地方,不需要考虑日志记录,权限验证,参数验证等问题,单纯的实现就好。 

通过这种方式实现的日志记录日志的记录形式是一致的,方便用户查阅。日志的记录信息也是比较完整的。当然对于一些复杂的接口,可能还需要添加额外的日志记录来描述更为详细的信息。

日志记录使用了log4net组件,搜索log4net,有很多详尽的介绍,这里就不说了。

你可能感兴趣的:(泛型)